\n"
-"\n"
+"\n"
"\n"
);
puts(
-"\n"
"
\n"
);
cgiMakeHiddenVar("phase", chooseTablePhase);
puts(
""
-"\n"
+"\n"
);
printf("To reset all user cart settings (including custom tracks), \n"
"click here .\n",
hgTextName());
printf("");
hgPositionsHelpHtml(organism, database);
webEnd();
}
static boolean allLetters(char *s)
/* returns true if the string only has letters number and underscores */
{
int i;
for (i = 0; i < strlen(s); i++)
if (!isalnum(s[i]) && s[i] != '_')
return FALSE;
return TRUE;
}
void checkIsAlpha(char *desc, char *word)
/* make sure that the table name doesn't have anything "weird" in it */
{
if (!allLetters(word))
webAbort("Error", "Invalid %s \"%s\".", desc, word);
}
boolean isSqlStringType(char *type)
{
return(strstr(type, "char") ||
strstr(type, "text") ||
strstr(type, "blob"));
}
char *getPosition(char **retChrom, int *retStart, int *retEnd)
/* Get position from cgi (not cart); use hgFind if necessary; return NULL
* if we had to display the gateway page or hgFind's selection page. */
{
char *pos = stripCommas(cgiOptionalString("position"));
char rawPos[64];
if ((pos != NULL) && (pos[0] != 0))
{
char *newPos = searchPosition(pos, retChrom, retStart, retEnd);
if (newPos == NULL)
exit(0);
else
{
if (! isGenome(newPos))
{
snprintf(rawPos, sizeof(rawPos), "%s:%d-%d",
chrom, winStart+1, winEnd);
newPos = rawPos;
}
return(cloneString(newPos));
}
}
else
return(NULL);
}
struct customTrack *getCustomTracks()
{
if (theCtList == NULL)
theCtList = customTracksParseCart(cart, &browserLines, NULL);
return(theCtList);
}
struct customTrack *lookupCt(char *name)
{
struct customTrack *ctList = getCustomTracks();
struct customTrack *ct;
for (ct=ctList; ct != NULL; ct=ct->next)
{
if (sameString(ct->tdb->tableName, name))
return ct;
}
return NULL;
}
boolean tableExists(char *table, char *db)
{
if (sameString(customTrackPseudoDb, db))
return (lookupCt(table) != NULL);
if (sameString(database, db))
return hTableExists(table);
if (sameString(hGetDb2(), db))
return hTableExists2(table);
else
{
errAbort("Unrecognized database name: %s", db);
return FALSE;
}
}
void checkTableExists(char *table)
{
if (! tableExists(table, getTableDb()))
webAbort("No data", "Table %s (%s) does not exist in database %s.",
getTableName(), table, getTableDb());
}
void checkTable2Exists(char *table)
{
if (! tableExists(table, getTable2Db()))
webAbort("No data", "Table %s (%s) does not exist in database %s.",
getTable2Name(), table, getTable2Db());
}
boolean existsAndEqual(char *var, char *value)
/* returns true is the given CGI var exists and equals value */
{
if (cgiOptionalString(var) != 0 && sameString(cgiOptionalString(var), value))
return TRUE;
else
return FALSE;
}
static boolean existsAndStartsWith(char *var, char *value)
/* returns true is the given CGI var exists and starts with value */
{
if (cgiOptionalString(var) != 0 && startsWith(value, cgiOptionalString(var)))
return TRUE;
else
return FALSE;
}
void pasteForm()
/* Put up form that lets them paste in keys. */
{
webStart(cart, "Table Browser: Paste in Names/Accessions for Batch Query");
puts(""
"Help ");
if (tableIsPositional)
{
puts(" Please paste in a list of names/accessions to match. "
"These may include * and ? wildcard characters.");
puts(" Note: name/accession matching is not supported for "
"non-positional tables.");
}
else
{
puts("
Sorry, pasting in names/accessions is not supported for "
"non-positional tables. (You can paste values into the "
"filter box of the field you would like to filter on the "
"Advanced Query page.)");
}
printf("
\n");
webEnd();
}
void uploadForm()
/* Put up upload form. */
{
webStart(cart, "Table Browser: Upload File of Names/Accessions for Batch Query");
puts(""
"Help ");
printf("\n",
hgTextName());
cgiContinueHiddenVar("org");
cgiContinueHiddenVar("db");
cgiMakeHiddenVar("position", "genome");
cgiMakeHiddenVar("table", getTableVar());
cgiMakeHiddenVar("phase", chooseTablePhase);
if (tableIsPositional)
cgiMakeHiddenVar("tbPosOrKeys", "keys");
cgiContinueHiddenVar("tbTrack");
cgiContinueHiddenVar("tbCustomTrack");
cgiContinueHiddenVar("table0");
cgiContinueHiddenVar("table1");
if (tableIsPositional)
{
puts("Please enter the name of a file in your computer containing a space, tab, or ");
puts("line separated list of the accessions/names you want to look up in the database.");
puts("Unlike in the paste option, wildcards don't work in this list.");
puts(" Note: name/accession matching is not supported for non-positional "
"tables.");
puts("Upload sequence: ");
puts("
\n");
}
else
{
puts("
Sorry, uploading names/accessions is not supported for "
"non-positional tables. (You can paste values into the "
"filter box of the field you would like to filter on the "
"Advanced Query page.)");
puts("
\n");
}
cartSaveSession(cart);
puts("
\n");
webEnd();
}
static void printSelectOptions(struct hashEl *optList, char *varName)
/* Print out an HTML select option for each element in a hashEl list.
* Mark as selected if it's the same as varName; strip prefix for display. */
{
struct hashEl *cur;
char *noPrefix;
char *curSetting = cartCgiUsualString(cart, varName, "");
for (cur = optList; cur != NULL; cur = cur->next)
{
if ((noPrefix = strchr(cur->name, '.')) != NULL)
noPrefix++;
else
noPrefix = cur->name;
if (sameString(curSetting, cur->name))
printf("%s \n",
cur->name, noPrefix);
else
printf("%s \n",
cur->name, noPrefix);
}
}
int compareTable(const void *elem1, const void *elem2)
/* compairs two hash element by name */
{
struct hashEl* a = *((struct hashEl **)elem1);
struct hashEl* b = *((struct hashEl **)elem2);
char *na, *nb;
if ((na = strchr(a->name, '.')) == NULL)
na = a->name;
if ((nb = strchr(b->name, '.')) == NULL)
nb = b->name;
return strcmp(na, nb);
}
boolean excludeTable(char *tbl)
/* Exclude these large tables. I think we should use a better algo. than
* hardcoding -- a count(*) cutoff? And should alert the user that the
* tables exist, but are being excluded due to size. */
{
return(sameString(tbl, "all_est") ||
sameString(tbl, "all_mrna"));
}
void getTableNames(char *db, struct sqlConnection *conn,
struct hashEl **retPosTableList,
struct hashEl **retNonposTableList)
/* separate tables in db into positional and nonpositional lists,
* with db added as a prefix to each name. */
{
struct hash *posTableHash = newHash(7);
struct hashEl *posTableList;
struct hash *nonposTableHash = newHash(7);
struct hashEl *nonposTableList;
struct sqlResult *sr;
char **row;
char query[256];
char name[128];
char chrom[32];
char post[64];
char fullName[128];
strcpy(query, "SHOW TABLES");
sr = sqlGetResult(conn, query);
while((row = sqlNextRow(sr)) != NULL)
{
if (excludeTable(row[0]))
continue;
/* if table name is of the form, chr*_random_* or chr*_*: */
if ( (sscanf(row[0], "chr%32[^_]_random_%64s", chrom, post) == 2) ||
(sscanf(row[0], "chr%32[^_]_hla_hap1_%64s", chrom, post) == 2) ||
(sscanf(row[0], "chr%32[^_]_hla_hap2_%64s", chrom, post) == 2) ||
(sscanf(row[0], "chr%32[^_]_%64s", chrom, post) == 2))
{
snprintf(name, sizeof(name), "chrN_%s", post);
// If a chrN_ table is already in the (positional) hash,
// don't bother looking up its fields.
if (hashLookup(posTableHash, name))
continue;
}
else
{
strncpy(name, row[0], sizeof(name));
}
snprintf(fullName, sizeof(fullName), "%s.%s", db, name);
if (hFindChromStartEndFieldsDb(db, row[0], query, query, query))
hashStoreName(posTableHash, cloneString(fullName));
else
hashStoreName(nonposTableHash, cloneString(fullName));
}
sqlFreeResult(&sr);
posTableList = hashElListHash(posTableHash);
slSort(&posTableList, compareTable);
nonposTableList = hashElListHash(nonposTableHash);
slSort(&nonposTableList, compareTable);
if (retPosTableList != NULL)
*retPosTableList = posTableList;
if (retNonposTableList != NULL)
*retNonposTableList = nonposTableList;
}
struct hashEl *getCustomTrackNames()
/* store custom track names in a hash (custom tracks are always positional) */
{
struct customTrack *ctList = getCustomTracks();
struct hash *ctTableHash = newHash(7);
struct hashEl *ctTableList;
struct customTrack *ct;
char fullName[128];
for (ct=ctList; ct != NULL; ct=ct->next)
{
snprintf(fullName, sizeof(fullName), "%s.%s",
customTrackPseudoDb, ct->tdb->tableName);
hashStoreName(ctTableHash, cloneString(fullName));
}
ctTableList = hashElListHash(ctTableHash);
slSort(&ctTableList, compareTable);
return(ctTableList);
}
void categorizeTables(struct hashEl **retPosTableList,
struct hashEl **retNonposTableList)
/* Return sorted lists of positional and non-positional table names
* from the current database and hgFixed. */
{
struct sqlConnection *conn;
struct hashEl *posTableList = NULL;
struct hashEl *nonposTableList = NULL;
struct hashEl *fixedPosTableList = NULL;
struct hashEl *fixedNonposTableList = NULL;
/* get table names from the database */
conn = hAllocConn(database);
getTableNames(database, conn, &posTableList, &nonposTableList);
hFreeConn(&conn);
/* get table names from hgFixed too */
conn = sqlConnect(hgFixed);
getTableNames(hgFixed, conn, &fixedPosTableList, &fixedNonposTableList);
sqlDisconnect(&conn);
/* append hgFixed db lists onto default db lists and return */
posTableList = slCat(posTableList, fixedPosTableList);
slSort(&posTableList, compareTable);
*retPosTableList = posTableList;
*retNonposTableList = slCat(nonposTableList, fixedNonposTableList);
slSort(retNonposTableList, compareTable);
}
void explainCoordSystem()
/* Our coord system is counter-intuitive to users. Warn them in advance to
* reduce the frequency with which they find this "bug" on their own and
* we have to explain it on the genome list. */
{
puts("Note: all start coordinates in our database are 0-based, not \n"
"1-based. See explanation \n"
"here .
");
}
void doChooseTable()
/* Offer the user choice of tracks/tables, positions, actions */
{
struct hashEl *ctPosTableList = NULL;
struct hashEl *posTableList;
struct hashEl *nonposTableList;
char *keyStr = getUserKeys();
char *posOrKeys;
webStart(cart, "Table Browser: %s %s: Choose a table",
hOrganism(database), freezeName);
printf("\n\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiContinueHiddenVar("tbUserKeys");
-puts("NOTE: This software has been replaced by a "
+puts("NOTE: This software has been replaced by a "
"newer version of the Table Browser. "
"This version of the tool is no longer "
"maintained or updated by UCSC; therefore, we can make no guarantees "
"about the completeness or correctness of the data returned. "
"We are happy to assist you in the transition to the new Table "
"Browser, which has many more features. Please "
"email our public mailing "
"list with questions or comments. "
- " ");
+ "
");
puts(""
"Help ");
ctPosTableList = getCustomTrackNames();
categorizeTables(&posTableList, &nonposTableList);
puts("
Choose a table: ");
printTrackDropList(database, onChangeTrack, "tbTrack");
printf("\n", onChangeCT);
printf("Custom tracks \n");
printSelectOptions(ctPosTableList, "tbCustomTrack");
puts(" ");
printf("\n", onChangePos);
printf("Positional tables \n");
printSelectOptions(posTableList, "table0");
puts(" ");
printf("\n", onChangeNonPos);
printf("Non-positional tables \n");
printSelectOptions(nonposTableList, "table1");
puts(" ");
hashElFreeList(&posTableList);
hashElFreeList(&nonposTableList);
puts("
Select items from tracks or positional tables by: ");
posOrKeys = cartCgiUsualString(cart, "tbPosOrKeys", "pos");
cgiMakeRadioButton("tbPosOrKeys", "pos", sameString(posOrKeys, "pos"));
puts("Position: ");
positionLookup(chooseTablePhase);
puts(" ");
cgiMakeRadioButton("tbPosOrKeys", "keys", !sameString(posOrKeys, "pos"));
puts("Item name/accession: ");
cgiMakeButton("phase", pasteNamesPhase);
printf(" ");
cgiMakeButton("phase", uploadNamesPhase);
if (keyStr != NULL)
{
puts(" Previously loaded names/accessions: ");
printFirstNWords(keyStr, 3, " ");
puts(" ");
}
puts(" Note: position and item name/accession lists are not applied "
"to non-positional tables.");
puts("
Choose an action: ");
cgiMakeButton("phase", oldAllFieldsPhase);
cgiMakeButton("phase", oldSeqOptionsPhase);
cgiMakeButton("phase", outputOptionsPhase);
cgiMakeButton("phase", descTablePhase);
puts("
");
explainCoordSystem();
hgPositionsHelpHtml(organism, database);
webEnd();
}
void getFullTableName(char *dest, char *newChrom, char *table)
/* given a chrom return the table name of the table selected by the user */
{
char post[64];
if (newChrom == NULL)
{
newChrom = hDefaultChrom();
}
chrom = newChrom;
if (allGenome)
{
winStart = 0;
winEnd = hChromSize(chrom);
}
if (sscanf(table, "chrN_%64s", post) == 1)
snprintf(dest, 256, "%s_%s", chrom, post);
else
strncpy(dest, table, 256);
/* make sure that the table name doesn't have anything "weird" in it */
checkIsAlpha("table name", dest);
}
void stringFilterOption(char *field, char *tableId, char *logOp)
/* Print out a table row with filter constraint options for a string/char. */
{
char name[128];
printf(" %s \n", field);
snprintf(name, sizeof(name), "dd%s_%s", tableId, field);
cgiMakeDropList(name, ddOpMenu, ddOpMenuSize,
cgiUsualString(name, ddOpMenu[0]));
puts(" match ");
snprintf(name, sizeof(name), "pat%s_%s", tableId, field);
cgiMakeTextVar(name, cgiUsualString(name, "*"), 20);
if (logOp == NULL)
logOp = "";
printf(" %s \n", logOp);
}
void numericFilterOption(char *field, char *fieldLabel, char *tableId,
char *logOp)
/* Print out a table row with filter constraint options for a number. */
{
char name[128];
printf(" %s \n", fieldLabel);
puts(" is ");
snprintf(name, sizeof(name), "cmp%s_%s", tableId, field);
cgiMakeDropList(name, cmpOpMenu, cmpOpMenuSize,
cgiUsualString(name, cmpOpMenu[0]));
puts(" \n");
snprintf(name, sizeof(name), "pat%s_%s", tableId, field);
cgiMakeTextVar(name, cgiUsualString(name, ""), 20);
if (logOp == NULL)
logOp = "";
printf(" %s \n", logOp);
}
void eqFilterOption(char *field, char *fieldLabel1, char *fieldLabel2,
char *tableId, char *logOp)
/* Print out a table row with filter constraint options for an equality
* comparison. */
{
char name[128];
printf(" %s \n", fieldLabel1);
puts(" is ");
snprintf(name, sizeof(name), "cmp%s_%s", tableId, field);
cgiMakeDropList(name, eqOpMenu, eqOpMenuSize,
cgiUsualString(name, eqOpMenu[0]));
/* make a dummy pat_ CGI var for consistency with other filter options */
snprintf(name, sizeof(name), "pat%s_%s", tableId, field);
cgiMakeHiddenVar(name, "0");
puts(" \n");
printf("%s\n", fieldLabel2);
if (logOp == NULL)
logOp = "";
printf(" %s \n", logOp);
}
void filterOptionsCustomTrack(char *table, char *tableId)
/* Print out an HTML table with form inputs for constraints on custom track */
{
struct customTrack *ct = lookupCt(table);
puts("");
if (ct->fieldCount >= 3)
{
stringFilterOption("chrom", tableId, " AND ");
numericFilterOption("chromStart", "chromStart", tableId, " AND ");
numericFilterOption("chromEnd", "chromEnd", tableId, " AND ");
}
if (ct->fieldCount >= 4)
{
stringFilterOption("name", tableId, " AND ");
}
if (ct->fieldCount >= 5)
{
numericFilterOption("score", "score", tableId, " AND ");
}
if (ct->fieldCount >= 6)
{
stringFilterOption("strand", tableId, " AND ");
}
if (ct->fieldCount >= 8)
{
numericFilterOption("thickStart", "thickStart", tableId, " AND ");
numericFilterOption("thickEnd", "thickEnd", tableId, " AND ");
}
if (ct->fieldCount >= 12)
{
numericFilterOption("blockCount", "blockCount", tableId, " AND ");
}
/* These are not bed fields, just extra constraints that we offer: */
if (ct->fieldCount >= 3)
{
numericFilterOption("chromLength", "(chromEnd - chromStart)", tableId,
(ct->fieldCount >= 8) ? " AND " : "");
}
if (ct->fieldCount >= 8)
{
numericFilterOption("thickLength", "(thickEnd - thickStart)",
tableId, " AND ");
eqFilterOption("compareStarts", "chromStart", "thickStart", tableId,
" AND ");
eqFilterOption("compareEnds", "chromEnd", "thickEnd", tableId, "");
}
puts("
");
}
void filterOptionsTableDb(char *fullTblName, char *db, char *tableId,
boolean filterWiggle)
/* Print out an HTML table with form inputs for constraints on table fields */
{
struct sqlConnection *conn = hAllocOrConnect(db);
struct sqlResult *sr;
char **row;
boolean gotFirst;
char query[256];
char name[128];
char *newVal;
snprintf(query, sizeof(query), "DESCRIBE %s", fullTblName);
sr = sqlGetResult(conn, query);
puts("\n");
puts("\n");
gotFirst = FALSE;
if (filterWiggle)
{
printf(" data value \n");
puts(" is \n");
snprintf(name, sizeof(name), "cmp%s_wigDataValue", tableId);
cgiMakeDropList(name, cmpOpMenu, cmpOpMenuSize,
cgiUsualString(name, cmpOpMenu[0]));
puts(" \n");
newVal = "";
snprintf(name, sizeof(name), "pat%s_wigDataValue", tableId);
cgiMakeTextVar(name, cgiUsualString(name, newVal), 20);
gotFirst = TRUE;
}
while ((row = sqlNextRow(sr)) != NULL)
{
if (! sameWord(row[1], "longblob"))
{
if (! gotFirst)
gotFirst = TRUE;
else
puts(" AND \n");
printf(" %s \n", row[0]);
if (isSqlStringType(row[1]))
{
snprintf(name, sizeof(name), "dd%s_%s", tableId, row[0]);
cgiMakeDropList(name, ddOpMenu, ddOpMenuSize,
cgiUsualString(name, ddOpMenu[0]));
puts(" match \n");
newVal = "*";
}
else
{
puts(" is \n");
snprintf(name, sizeof(name), "cmp%s_%s", tableId, row[0]);
cgiMakeDropList(name, cmpOpMenu, cmpOpMenuSize,
cgiUsualString(name, cmpOpMenu[0]));
puts(" \n");
newVal = "";
}
snprintf(name, sizeof(name), "pat%s_%s", tableId, row[0]);
cgiMakeTextVar(name, cgiUsualString(name, newVal), 20);
}
}
sqlFreeResult(&sr);
hFreeOrDisconnect(&conn);
puts("
\n");
puts(" ");
snprintf(name, sizeof(name), "log_rawQuery%s", tableId);
cgiMakeDropList(name, logOpMenu, logOpMenuSize,
cgiUsualString(name, logOpMenu[0]));
puts("Free-form query: ");
snprintf(name, sizeof(name), "rawQuery%s", tableId);
cgiMakeTextVar(name, cgiUsualString(name, ""), 50);
puts(" ");
puts("
");
}
void parseNum(char *fieldName, struct kxTok **tok, struct dyString *q)
{
if (*tok == NULL)
webAbort("Error", "Parse error when reading number for field %s.",
fieldName);
if ((*tok)->type == kxtSub)
{
// unary '-': negative number, pass through to SQL.
dyStringAppend(q, (*tok)->string);
*tok = (*tok)->next;
}
if ((*tok)->type == kxtString)
{
if (! isdigit((*tok)->string[0]))
webAbort("Error", "Parse error when reading number for field %s.",
fieldName);
dyStringAppend(q, (*tok)->string);
*tok = (*tok)->next;
}
else
{
webAbort("Error", "Parse error when reading number for field %s: Incorrect token type %d for token \"%s\"",
fieldName, (*tok)->type, (*tok)->string);
}
}
void constrainNumber(char *fieldName, char *op, char *pat, char *log,
struct dyString *clause)
{
struct kxTok *tokList, *tokPtr;
int i;
boolean legit;
if (fieldName == NULL || op == NULL || pat == NULL || log == NULL)
webAbort("Error", "CGI var error: not all required vars were defined for field %s.", fieldName);
/* complain if op is not a legitimate value */
legit = FALSE;
for (i=0; i < cmpOpMenuSize; i++)
{
if (sameString(cmpOpMenu[i], op))
{
legit = TRUE;
break;
}
}
if (! legit)
webAbort("Error", "Illegal comparison operator \"%s\"", op);
/* tokenize (don't expect wildcards) */
tokPtr = tokList = kxTokenize(pat, FALSE);
if (clause->stringSize > 0)
dyStringPrintf(clause, " %s ", log);
else
dyStringAppend(clause, "(");
dyStringPrintf(clause, "(%s %s ", fieldName, op);
parseNum(fieldName, &tokPtr, clause);
dyStringAppend(clause, ")");
slFreeList(&tokList);
}
void constrainRange(char *fieldName, char *pat, char *log,
struct dyString *clause)
{
struct kxTok *tokList, *tokPtr;
if (fieldName == NULL || pat == NULL || log == NULL)
webAbort("Error", "CGI var error: not all required vars were defined for field %s.", fieldName);
/* tokenize (don't expect wildcards) */
tokPtr = tokList = kxTokenize(pat, FALSE);
if (clause->stringSize > 0)
dyStringPrintf(clause, " %s ", log);
else
dyStringAppend(clause, "(");
dyStringPrintf(clause, "((%s >= ", fieldName);
parseNum(fieldName, &tokPtr, clause);
dyStringPrintf(clause, ") && (%s <= ", fieldName);
while (tokPtr != NULL && tokPtr->type == kxtPunct)
tokPtr = tokPtr->next;
parseNum(fieldName, &tokPtr, clause);
dyStringAppend(clause, "))");
slFreeList(&tokList);
}
void constrainPattern(char *fieldName, char *dd, char *pat, char *log,
struct dyString *clause)
{
struct kxTok *tokList, *tokPtr;
boolean needOr = FALSE;
char *cmp, *or, *ptr;
int i;
boolean legit;
if (fieldName == NULL || dd == NULL || pat == NULL || log == NULL)
webAbort("Error", "CGI var error: not all required vars were defined for field %s.", fieldName);
/* complain if dd is not a legitimate value */
legit = FALSE;
for (i=0; i < ddOpMenuSize; i++)
{
if (sameString(ddOpMenu[i], dd))
{
legit = TRUE;
break;
}
}
if (! legit)
webAbort("Error", "Illegal does/doesn't value \"%s\"", dd);
/* tokenize (do allow wildcards, SQL wildcards, hyphens) */
tokList = kxTokenizeFancy(pat, TRUE, TRUE, TRUE);
/* The subterms are joined by OR if dd="does", AND if dd="doesn't" */
or = sameString(dd, "does") ? " OR " : " AND ";
cmp = sameString(dd, "does") ? "LIKE" : "NOT LIKE";
if (clause->stringSize > 0)
dyStringPrintf(clause, " %s ", log);
else
dyStringAppend(clause, "(");
dyStringAppend(clause, "(");
for (tokPtr = tokList; tokPtr != NULL; tokPtr = tokPtr->next)
{
if (tokPtr->type == kxtWildString || tokPtr->type == kxtString ||
/* Allow these types for strand matches too: */
tokPtr->type == kxtSub || tokPtr->type == kxtAdd)
{
if (needOr)
dyStringAppend(clause, or);
/* Replace normal wildcard characters with SQL: */
while ((ptr = strchr(tokPtr->string, '?')) != NULL)
*ptr = '_';
while ((ptr = strchr(tokPtr->string, '*')) != NULL)
*ptr = '%';
dyStringPrintf(clause, "(%s %s \"%s\")",
fieldName, cmp, tokPtr->string);
needOr = TRUE;
}
else if (tokPtr->type == kxtEnd)
break;
else
{
webAbort("Error", "Match pattern parse error for field %s: bad token type (%d) for this word: \"%s\".",
fieldName, tokPtr->type, tokPtr->string);
}
}
dyStringAppend(clause, ")");
slFreeList(&tokList);
}
void constrainFreeForm(char *rawQuery, struct dyString *clause)
/* Let the user type in an expression that may contain
* - field names
* - parentheses
* - comparison/arithmetic/logical operators
* - numbers
* - patterns with wildcards
* Make sure they don't use any SQL reserved words, ;'s, etc.
* Let SQL handle the actual parsing of nested expressions etc. -
* this is just a token cop. */
{
struct kxTok *tokList, *tokPtr;
char *ptr;
int numLeftParen, numRightParen;
if ((rawQuery == NULL) || (rawQuery[0] == 0))
return;
/* tokenize (do allow wildcards, and include quotes.) */
kxTokIncludeQuotes(TRUE);
tokList = kxTokenizeFancy(rawQuery, TRUE, TRUE, TRUE);
/* to be extra conservative, wrap the whole expression in parens. */
dyStringAppend(clause, "(");
numLeftParen = numRightParen = 0;
for (tokPtr = tokList; tokPtr != NULL; tokPtr = tokPtr->next)
{
if ((tokPtr->type == kxtEquals) ||
(tokPtr->type == kxtGT) ||
(tokPtr->type == kxtGE) ||
(tokPtr->type == kxtLT) ||
(tokPtr->type == kxtLE) ||
(tokPtr->type == kxtAnd) ||
(tokPtr->type == kxtOr) ||
(tokPtr->type == kxtNot) ||
(tokPtr->type == kxtAdd) ||
(tokPtr->type == kxtSub) ||
(tokPtr->type == kxtDiv))
{
dyStringAppend(clause, tokPtr->string);
}
else if (tokPtr->type == kxtOpenParen)
{
dyStringAppend(clause, tokPtr->string);
numLeftParen++;
}
else if (tokPtr->type == kxtCloseParen)
{
dyStringAppend(clause, tokPtr->string);
numRightParen++;
}
else if ((tokPtr->type == kxtWildString) ||
(tokPtr->type == kxtString))
{
char *word = cloneString(tokPtr->string);
toUpperN(word, strlen(word));
if (startsWith("SQL_", word) ||
startsWith("MYSQL_", word) ||
sameString("ALTER", word) ||
sameString("BENCHMARK", word) ||
sameString("CHANGE", word) ||
sameString("CREATE", word) ||
sameString("DELAY", word) ||
sameString("DELETE", word) ||
sameString("DROP", word) ||
sameString("FLUSH", word) ||
sameString("GET_LOCK", word) ||
sameString("GRANT", word) ||
sameString("INSERT", word) ||
sameString("KILL", word) ||
sameString("LOAD", word) ||
sameString("LOAD_FILE", word) ||
sameString("LOCK", word) ||
sameString("MODIFY", word) ||
sameString("PROCESS", word) ||
sameString("QUIT", word) ||
sameString("RELEASE_LOCK", word) ||
sameString("RELOAD", word) ||
sameString("REPLACE", word) ||
sameString("REVOKE", word) ||
sameString("SELECT", word) ||
sameString("SESSION_USER", word) ||
sameString("SHOW", word) ||
sameString("SYSTEM_USER", word) ||
sameString("UNLOCK", word) ||
sameString("UPDATE", word) ||
sameString("USE", word) ||
sameString("USER", word) ||
sameString("VERSION", word))
{
webAbort("Error", "Illegal SQL word \"%s\" in free-form query string",
tokPtr->string);
}
else if (sameString("*", tokPtr->string))
{
// special case for multiplication in a wildcard world
dyStringPrintf(clause, " %s ", tokPtr->string);
}
else
{
/* Replace normal wildcard characters with SQL: */
while ((ptr = strchr(tokPtr->string, '?')) != NULL)
*ptr = '_';
while ((ptr = strchr(tokPtr->string, '*')) != NULL)
*ptr = '%';
dyStringPrintf(clause, " %s ", tokPtr->string);
}
}
else if (tokPtr->type == kxtEnd)
{
break;
}
else
{
webAbort("Error", "Unrecognized token \"%s\" in free-form query string",
tokPtr->string);
}
}
dyStringAppend(clause, ")");
if (numLeftParen != numRightParen)
webAbort("Error", "Unequal number of left parentheses (%d) and right parentheses (%d) in free-form query expression",
numLeftParen, numRightParen);
slFreeList(&tokList);
}
char *constrainFields(char *tableId)
/* If the user specified constraints, append SQL conditions (suitable
* for a WHERE clause) to q. */
{
struct cgiVar *current;
struct dyString *freeClause = newDyString(512);
struct dyString *andClause = newDyString(512);
struct dyString *clause;
char *fieldName;
char *rawQuery;
char *rQLogOp;
char *dd, *cmp, *pat;
char varName[128];
char *ret;
int tableIndex = 0;
if (tableId == NULL)
{
tableId = "";
tableIndex = 0;
}
if (sameString(tableId,"2"))
tableIndex = 1;
dyStringClear(andClause);
for (current = cgiVarList(); current != NULL; current = current->next)
{
/* Look for pattern variable associated with each field. */
snprintf(varName, sizeof(varName), "pat%s_", tableId);
if (startsWith(varName, current->name))
{
fieldName = current->name + strlen(varName);
/* make sure that the field name doesn't have anything "weird" in it */
checkIsAlpha("field name", fieldName);
pat = current->val;
snprintf(varName, sizeof(varName), "dd%s_%s", tableId, fieldName);
dd = cgiOptionalString(varName);
snprintf(varName, sizeof(varName), "cmp%s_%s", tableId, fieldName);
cmp = cgiOptionalString(varName);
if (sameString(fieldName,"wigDataValue"))
{
if (strlen(cmp)>0 && differentWord(cmp,"ignored"))
wiggleConstraints(cmp, pat, tableIndex);
}
/* If it's a null constraint, skip it. */
if ( (dd != NULL &&
(pat == NULL || pat[0] == 0 ||
sameString(trimSpaces(pat), "*"))) ||
(cmp != NULL && sameString(cmp, "ignored")) ||
sameString(fieldName,"wigDataValue") )
continue;
/* Otherwise, expect it to be a well-formed constraint and tack
* it on to the clause. */
clause = andClause;
if (cmp != NULL && sameString(cmp, "in range"))
constrainRange(fieldName, pat, "AND", clause);
else if (cmp != NULL)
constrainNumber(fieldName, cmp, pat, "AND", clause);
else
constrainPattern(fieldName, dd, pat, "AND", clause);
}
}
if (andClause->stringSize > 0)
dyStringAppend(andClause, ")");
dyStringClear(freeClause);
snprintf(varName, sizeof(varName), "rawQuery%s", tableId);
rawQuery = cgiOptionalString(varName);
snprintf(varName, sizeof(varName), "log_rawQuery%s", tableId);
rQLogOp = cgiOptionalString(varName);
constrainFreeForm(rawQuery, freeClause);
// force rQLogOp to a legit value:
if ((rQLogOp != NULL) && (! sameString("AND", rQLogOp)))
rQLogOp = "OR";
if (freeClause->stringSize > 0 && andClause->stringSize > 0)
dyStringPrintf(freeClause, " %s ", rQLogOp);
if (freeClause->stringSize > 0)
{
dyStringAppend(freeClause, andClause->string);
}
else
{
dyStringAppend(freeClause, andClause->string);
}
ret = cloneString(freeClause->string);
freeDyString(&freeClause);
freeDyString(&andClause);
return ret;
}
void cgiToCharFilter(char *dd, char *pat, enum charFilterType *retCft,
char **retVals, boolean *retInv)
/* Given a "does/doesn't" and a (list of) literal chars from CGI, fill in
* retCft, retVals and retInv to make a filter. */
{
char *vals, *ptrs[32];
int numWords;
int i;
assert(retCft != NULL);
assert(retVals != NULL);
assert(retInv != NULL);
assert(sameString(dd, "does") || sameString(dd, "doesn't"));
/* catch null-constraint cases. ? will be treated as a literal match,
* which would make sense for bed strand and maybe other single-char things: */
if (pat == NULL)
pat = "";
pat = trimSpaces(pat);
if ((pat[0] == 0) || sameString(pat, "*"))
{
*retCft = cftIgnore;
return;
}
*retCft = cftMultiLiteral;
numWords = chopByWhite(pat, ptrs, ArraySize(ptrs));
vals = needMem((numWords+1) * sizeof(char));
for (i=0; i < numWords; i++)
vals[i] = ptrs[i][0];
vals[i] = 0;
*retVals = vals;
*retInv = sameString("doesn't", dd);
}
void cgiToStringFilter(char *dd, char *pat, enum stringFilterType *retSft,
char ***retVals, boolean *retInv)
/* Given a "does/doesn't" and a (list of) regexps from CGI, fill in
* retCft, retVals and retInv to make a filter. */
{
char **vals, *ptrs[32];
int numWords;
int i;
assert(retSft != NULL);
assert(retVals != NULL);
assert(retInv != NULL);
assert(sameString(dd, "does") || sameString(dd, "doesn't"));
/* catch null-constraint cases: */
if (pat == NULL)
pat = "";
pat = trimSpaces(pat);
if ((pat[0] == 0) || sameString(pat, "*"))
{
*retSft = sftIgnore;
return;
}
*retSft = sftMultiRegexp;
numWords = chopByWhite(pat, ptrs, ArraySize(ptrs));
vals = needMem((numWords+1) * sizeof(char *));
for (i=0; i < numWords; i++)
vals[i] = cloneString(ptrs[i]);
vals[i] = NULL;
*retVals = vals;
*retInv = sameString("doesn't", dd);
}
void cgiToIntFilter(char *cmp, char *pat, enum numericFilterType *retNft,
int **retVals)
/* Given a comparison operator and a (pair of) integers from CGI, fill in
* retNft and retVals to make a filter. */
{
char *ptrs[3];
int *vals;
int numWords;
assert(retNft != NULL);
assert(retVals != NULL);
/* catch null-constraint cases: */
if (pat == NULL)
pat = "";
pat = trimSpaces(pat);
if ((pat[0] == 0) || sameString(pat, "*") || sameString(cmp, "ignored"))
{
*retNft = nftIgnore;
return;
}
else if (sameString(cmp, "in range"))
{
*retNft = nftInRange;
numWords = chopString(pat, " \t,", ptrs, ArraySize(ptrs));
if (numWords != 2)
errAbort("For \"in range\" constraint, you must give two numbers separated by whitespace or comma.");
vals = needMem(2 * sizeof(int));
vals[0] = atoi(ptrs[0]);
vals[1] = atoi(ptrs[1]);
if (vals[0] > vals[1])
{
int tmp = vals[0];
vals[0] = vals[1];
vals[1] = tmp;
}
*retVals = vals;
}
else
{
if (sameString(cmp, "<"))
*retNft = nftLessThan;
else if (sameString(cmp, "<="))
*retNft = nftLTE;
else if (sameString(cmp, "="))
*retNft = nftEqual;
else if (sameString(cmp, "!="))
*retNft = nftNotEqual;
else if (sameString(cmp, ">="))
*retNft = nftGTE;
else if (sameString(cmp, ">"))
*retNft = nftGreaterThan;
else
errAbort("Unrecognized comparison operator %s", cmp);
vals = needMem(sizeof(int));
vals[0] = atoi(pat);
*retVals = vals;
}
}
struct bedFilter *constrainBedFields(char *tableId)
/* If the user specified constraints, then translate them to a bedFilter. */
{
struct bedFilter *bf;
struct cgiVar *current;
char *fieldName;
char *dd, *cmp, *pat;
char varName[128];
int *trash;
if (tableId == NULL)
tableId = "";
AllocVar(bf);
for (current = cgiVarList(); current != NULL; current = current->next)
{
/* Look for pattern variable associated with each field. */
snprintf(varName, sizeof(varName), "pat%s_", tableId);
if (startsWith(varName, current->name))
{
fieldName = current->name + strlen(varName);
checkIsAlpha("field name", fieldName);
pat = cloneString(current->val);
snprintf(varName, sizeof(varName), "dd%s_%s", tableId, fieldName);
dd = cgiOptionalString(varName);
snprintf(varName, sizeof(varName), "cmp%s_%s", tableId, fieldName);
cmp = cgiOptionalString(varName);
if (sameString("chrom", fieldName))
cgiToStringFilter(dd, pat, &(bf->chromFilter), &(bf->chromVals),
&(bf->chromInvert));
else if (sameString("chromStart", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->chromStartFilter), &(bf->chromStartVals));
else if (sameString("chromEnd", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->chromEndFilter), &(bf->chromEndVals));
else if (sameString("name", fieldName))
cgiToStringFilter(dd, pat, &(bf->nameFilter), &(bf->nameVals),
&(bf->nameInvert));
else if (sameString("score", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->scoreFilter), &(bf->scoreVals));
else if (sameString("strand", fieldName))
cgiToCharFilter(dd, pat, &(bf->strandFilter), &(bf->strandVals),
&(bf->strandInvert));
else if (sameString("thickStart", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->thickStartFilter), &(bf->thickStartVals));
else if (sameString("thickEnd", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->thickEndFilter), &(bf->thickEndVals));
else if (sameString("blockCount", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->blockCountFilter), &(bf->blockCountVals));
else if (sameString("chromLength", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->chromLengthFilter), &(bf->chromLengthVals));
else if (sameString("thickLength", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->thickLengthFilter), &(bf->thickLengthVals));
else if (sameString("compareStarts", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->compareStartsFilter), &trash);
else if (sameString("compareEnds", fieldName))
cgiToIntFilter(cmp, pat,
&(bf->compareEndsFilter), &trash);
}
}
return(bf);
}
void preserveConstraints(char *fullTblName, char *db, char *tableId)
/* Add CGI variables for filtering constraints, so they will be passed to
* the next page. Also parse the constraints and do a null query with them
* in order to catch any syntax errors sooner rather than later. */
{
struct cgiVar *current;
char *constraints = constrainFields(tableId);
char varName[128];
if ((constraints != NULL) && (constraints[0] != 0) &&
(! sameString(customTrackPseudoDb, db)))
{
struct sqlConnection *conn = hAllocOrConnect(db);
struct sqlResult *sr;
struct dyString *query = newDyString(512);
// Null query will cause errAbort if there's a syntax error, no-op if OK.
dyStringPrintf(query, "SELECT 1 FROM %s WHERE 0 AND %s",
fullTblName, constraints);
sr = sqlGetResult(conn, query->string);
dyStringFree(&query);
sqlFreeResult(&sr);
hFreeOrDisconnect(&conn);
}
if (tableId == NULL)
tableId = "";
for (current = cgiVarList(); current != NULL; current = current->next)
{
/* Look for pattern variable associated with each field. */
snprintf(varName, sizeof(varName), "pat%s_", tableId);
if (startsWith(varName, current->name))
cgiMakeHiddenVar(current->name, current->val);
snprintf(varName, sizeof(varName), "dd%s_", tableId);
if (startsWith(varName, current->name))
cgiMakeHiddenVar(current->name, current->val);
snprintf(varName, sizeof(varName), "cmp%s_", tableId);
if (startsWith(varName, current->name))
cgiMakeHiddenVar(current->name, current->val);
snprintf(varName, sizeof(varName), "log_rawQuery%s", tableId);
if (sameString(varName, current->name))
cgiMakeHiddenVar(current->name, current->val);
snprintf(varName, sizeof(varName), "rawQuery%s", tableId);
if (sameString(varName, current->name))
{
// Replace " with ' in rawQuery; the value will be double-quoted
// in the form, and double-quotes in the value really mess it up.
subChar(current->val, '"', '\'');
cgiMakeHiddenVar(current->name, current->val);
}
}
}
void preserveTable2()
{
char *table2 = getTable2Name();
char *op = cgiOptionalString("tbIntersectOp");
if ((table2 != NULL) && (table2[0] != 0) && (op != NULL))
{
char *db2 = getTable2Db();
char fullTableName2[256];
cgiContinueHiddenVar("table2");
cgiContinueHiddenVar("tbIntersectOp");
cgiMakeHiddenVar("tbMoreThresh", cgiUsualString("tbMoreThresh", "0"));
cgiMakeHiddenVar("tbLessThresh", cgiUsualString("tbLessThresh", "100"));
cgiContinueHiddenVar("tbInvertTable");
cgiContinueHiddenVar("tbInvertTable2");
getFullTableName(fullTableName2, chrom, table2);
preserveConstraints(fullTableName2, db2, "2");
}
}
struct hTableInfo *ctToHti(struct customTrack *ct)
/* Create an hTableInfo from a customTrack. */
{
struct hTableInfo *hti;
if (ct == NULL)
return(NULL);
AllocVar(hti);
hti->rootName = cloneString(ct->tdb->tableName);
hti->isPos = TRUE;
hti->isSplit = FALSE;
hti->hasBin = FALSE;
hti->type = cloneString(ct->tdb->type);
if (ct->fieldCount >= 3)
{
strncpy(hti->chromField, "chrom", 32);
strncpy(hti->startField, "chromStart", 32);
strncpy(hti->endField, "chromEnd", 32);
}
if (ct->fieldCount >= 4)
{
strncpy(hti->nameField, "name", 32);
}
if (ct->fieldCount >= 5)
{
strncpy(hti->scoreField, "score", 32);
}
if (ct->fieldCount >= 6)
{
strncpy(hti->strandField, "strand", 32);
}
if (ct->fieldCount >= 8)
{
strncpy(hti->cdsStartField, "thickStart", 32);
strncpy(hti->cdsEndField, "thickEnd", 32);
hti->hasCDS = TRUE;
}
if (ct->fieldCount >= 12)
{
strncpy(hti->countField, "blockCount", 32);
strncpy(hti->startsField, "chromStarts", 32);
strncpy(hti->endsSizesField, "blockSizes", 32);
hti->hasBlocks = TRUE;
}
return(hti);
}
struct hTableInfo *maybeGetHti(char *db, char *table)
/* Return primary table info. */
{
struct hTableInfo *hti = NULL;
if (sameString(customTrackPseudoDb, db))
{
struct customTrack *ct = lookupCt(table);
hti = ctToHti(ct);
}
else
{
char *track;
if (startsWith("chrN_", table))
track = table + strlen("chrN_");
else
track = table;
hti = hFindTableInfoDb(db, chrom, track);
}
return(hti);
}
struct hTableInfo *getHti(char *db, char *table)
/* Return primary table info. */
{
struct hTableInfo *hti = maybeGetHti(db, table);
if (hti == NULL)
webAbort("Error", "Could not find table info for table %s in db %s",
table, db);
return(hti);
}
struct hTableInfo *getOutputHti()
/* Return effective table info for the output. If we're doing a
* base-pair-wise intersection/union of 2 tables, this will be a
* bed4 that isn't a track (unless user makes it a custom track).
* Otherwise this will just be the primary table info. */
{
char *db = getTableDb();
char *table = getTableName();
struct hTableInfo *hti = getHti(db, table);
char *table2 = getTable2Name();
char *op = cgiOptionalString("tbIntersectOp");
if ((table2 != NULL) && (table2[0] != 0) && (op != NULL))
{
char buf[128];
if (sameString("and", op) || sameString("or", op))
{
struct hTableInfo *effHti;
AllocVar(effHti);
snprintf(buf, sizeof(buf), "%s_%s_%s", table, op, table2);
effHti->rootName = cloneString(buf);
effHti->isPos = TRUE;
effHti->isSplit = FALSE;
effHti->hasBin = FALSE;
snprintf(effHti->chromField, 32, "N/A");
snprintf(effHti->startField, 32, "N/A");
snprintf(effHti->endField, 32, "N/A");
snprintf(effHti->nameField, 32, "N/A");
effHti->scoreField[0] = 0;
effHti->strandField[0] = 0;
effHti->cdsStartField[0] = 0;
effHti->cdsEndField[0] = 0;
effHti->countField[0] = 0;
effHti->startsField[0] = 0;
effHti->endsSizesField[0] = 0;
effHti->hasCDS = FALSE;
effHti->hasBlocks = FALSE;
strcpy(buf, "bed 4");
effHti->type = cloneString(buf);
return(effHti);
}
else
{
snprintf(buf, sizeof(buf), "%s_%s_%s", hti->rootName, op, table2);
hti->rootName = cloneString(buf);
}
}
return(hti);
}
boolean isWiggle(char *db, char *table)
/* Return TRUE if db.table is a wiggle. */
{
boolean typeWiggle = FALSE;
if (db != NULL && table != NULL)
{
if (sameString(customTrackPseudoDb, db))
{
struct customTrack *ct = lookupCt(table);
if (ct && ct->wiggle)
typeWiggle = FALSE; /* TEMPORARY, until we handle this case */
/* this is actually the TRUE condition */
}
else
{
struct hTableInfo *hti = maybeGetHti(db, table);
typeWiggle = (hti != NULL && HTI_IS_WIGGLE);
}
}
return(typeWiggle);
}
void doOutputOptions()
/* print out a form with output table format & filtering options */
{
struct hashEl *ctPosTableList = NULL;
struct hashEl *posTableList = NULL;
struct hashEl *nonposTableList = NULL;
char *table = getTableName();
char *db = getTableDb();
saveChooseTableState();
webStart(cart, "Table Browser: %s %s: %s", hOrganism(database),freezeName, outputOptionsPhase);
checkTableExists(fullTableName);
printf("\n\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiMakeHiddenVar("table", getTableVar());
displayPosition();
printf("
Select Output Format for %s \n", table);
puts(""
"Help ");
if (tableIsPositional)
if (typeWiggle)
cgiMakeDropList("outputType", outputTypeWiggleMenu,
outputTypeWiggleMenuSize,
cartCgiUsualString(cart, "outputType", outputTypeWiggleMenu[0]));
else
cgiMakeDropList("outputType", outputTypePosMenu, outputTypePosMenuSize,
cartCgiUsualString(cart, "outputType", outputTypePosMenu[0]));
else
cgiMakeDropList("outputType", outputTypeNonPosMenu,
outputTypeNonPosMenuSize,
cartCgiUsualString(cart, "outputType", outputTypeNonPosMenu[0]));
cgiMakeButton("phase", getOutputPhase);
if (tableIsPositional)
explainCoordSystem();
printf("
(Optional) Filter %s Records by Field Values ",
table);
puts(""
"Help ");
if (sameString(customTrackPseudoDb, db))
filterOptionsCustomTrack(table, "");
else
filterOptionsTableDb(fullTableName, db, "", typeWiggle);
cgiMakeButton("phase", getOutputPhase);
if (tableIsPositional)
{
puts("
(Optional) Intersect Results with Another Table ");
puts(""
"Help ");
puts("Note: Output Format must be FASTA, BED, Hyperlinks, GTF \n"
"or Summary/Statistics "
"for this feature.
");
ctPosTableList = getCustomTrackNames();
categorizeTables(&posTableList, &nonposTableList);
puts("Choose a second table:");
printTrackDropList(database, onChangeTrack2, "tbTrack2");
printf("\n", onChangeCT2);
printf("Custom tracks \n");
printSelectOptions(ctPosTableList, "tbCustomTrack2");
puts(" ");
printf("", onChangePos2);
printf("Positional tables \n");
printSelectOptions(posTableList, "table2");
puts(" ");
hashElFreeList(&posTableList);
hashElFreeList(&nonposTableList);
puts("
");
cgiMakeButton("phase", intersectOptionsPhase);
}
puts("
");
webEnd();
}
void bedFilterBatch(struct bed **bedListPtr)
/* If position is batch, filter by name. */
{
if (isBatch())
{
struct bed *bedListOut = NULL;
char *keyStr = getUserKeys();
char *word;
if (cgiVarExists("tbShowUploadResults"))
{
struct hash *nameHash = newHash(18);
while ((word = nextWord(&keyStr)) != NULL)
{
hashAdd(nameHash, word, NULL);
}
bedListOut = bedFilterByNameHash(*bedListPtr, nameHash);
hashFree(&nameHash);
}
else
{
struct slName *wildNames = NULL, *wild=NULL;
while ((word = nextWord(&keyStr)) != NULL)
{
wild = slNameNew(word);
slAddHead(&wildNames, wild);
}
bedListOut = bedFilterByWildNames(*bedListPtr, wildNames);
slFreeList(&wildNames);
}
bedFreeList(bedListPtr);
*bedListPtr = bedListOut;;
}
}
struct bed *bitsToBed4List(Bits *bits, int bitSize, char *chrom, int minSize,
int rangeStart, int rangeEnd)
/* Translate ranges of set bits to bed 4 items. */
{
struct bed *bedList = NULL, *bed;
int i;
boolean thisBit, lastBit;
int start = 0;
int end;
int id = 0;
char name[128];
if (rangeStart < 0)
rangeStart = 0;
if (rangeEnd > bitSize)
rangeEnd = bitSize;
/* We depend on extra zero BYTE at end in case bitNot was used on bits. */
thisBit = FALSE;
for (i=0; i < bitSize+8; ++i)
{
lastBit = thisBit;
thisBit = bitReadOne(bits, i);
if (thisBit)
{
if (!lastBit)
start = i;
}
else
{
end = i;
if (end >= bitSize)
end = bitSize - 1;
// Lop off elements that go all the way to the beginning/end of the
// chrom... unless our range actually includes the beginning/end.
// (That can happen with the AND/OR of two NOT's...)
if (lastBit &&
((end - start) >= minSize) &&
((rangeStart == 0) || (start > 0)) &&
((rangeEnd == bitSize) || (end < bitSize)))
{
AllocVar(bed);
bed->chrom = cloneString(chrom);
bed->chromStart = start;
bed->chromEnd = end;
snprintf(name, sizeof(name), "%s.%d", chrom, ++id);
bed->name = cloneString(name);
slAddHead(&bedList, bed);
}
}
}
slReverse(&bedList);
return(bedList);
}
int countBasesOverlap(struct bed *bedItem, Bits *bits, boolean hasBlocks)
/* Return the number of bases belonging to bedItem covered by bits. */
{
int count = 0;
int i, j;
if (hasBlocks)
{
for (i=0; i < bedItem->blockCount; i++)
{
int start = bedItem->chromStart + bedItem->chromStarts[i];
int end = start + bedItem->blockSizes[i];
for (j=start; j < end; j++)
if (bitReadOne(bits, j))
count++;
}
}
else
{
for (i=bedItem->chromStart; i < bedItem->chromEnd; i++)
if (bitReadOne(bits, i))
count++;
}
return(count);
}
struct bed *getBedList(boolean ignoreConstraints, char *onlyThisChrom)
/* For any positional table output: get the features selected by the user
* and return them as a bed list. This is where table intersection happens. */
{
struct slName *chromList, *chromPtr;
struct bed *bedList = NULL, *bedListT1 = NULL, *bedListChrom = NULL;
char *db = getTableDb();
char *table = getTableName();
struct hTableInfo *hti = getHti(db, table);
char *constraints;
char *table2 = getTable2Name();
char *op = cgiOptionalString("tbIntersectOp");
char *track = getTrackName();
int i;
if (! tableExists(fullTableName, db))
return NULL;
constraints = constrainFields(NULL);
if (ignoreConstraints ||
((constraints != NULL) && (constraints[0] == 0)))
constraints = NULL;
if (onlyThisChrom != NULL)
chromList = newSlName(onlyThisChrom);
else if (allGenome)
chromList = hAllChromNames();
else
chromList = newSlName(chrom);
for (chromPtr=chromList; chromPtr != NULL; chromPtr = chromPtr->next)
{
bedListChrom = NULL;
getFullTableName(fullTableName, chromPtr->name, table);
if (! tableExists(fullTableName, db))
continue;
if (sameString(customTrackPseudoDb, db))
{
struct customTrack *ct = lookupCt(table);
struct bedFilter *bf = NULL;
if (! ignoreConstraints)
bf = constrainBedFields(NULL);
bedListT1 = bedFilterListInRange(ct->bedList, bf,
chrom, winStart, winEnd);
}
else
{
if (typeWiggle)
wigMakeBedList(db, fullTableName, chromPtr->name,
constraints, WIG_TABLE_1);
if (typeWiggle && (bedListWig[WIG_TABLE_1] != (struct bed *)NULL))
bedListT1 = bedListWig[WIG_TABLE_1];
else
bedListT1 = hGetBedRangeDb(db, fullTableName, chrom, winStart,
winEnd, constraints);
}
bedFilterBatch(&bedListT1);
/* If 2 tables are named, get their intersection. */
if ((table2 != NULL) && (table2[0] != 0) && (op != NULL))
{
struct featureBits *fbListT2 = NULL;
struct bed *bed;
Bits *bitsT2;
int moreThresh = cgiOptionalInt("tbMoreThresh", 0);
int lessThresh = cgiOptionalInt("tbLessThresh", 100);
boolean invTable = cgiBoolean("tbInvertTable");
boolean invTable2 = cgiBoolean("tbInvertTable2");
char *track2 = getTrack2Name();
char *db2 = getTable2Db();
char *constraints2 = constrainFields("2");
char fullTableName2[256];
int chromSize = hChromSize(chromPtr->name);
boolean isBpWise = (sameString("and", op) || sameString("or", op));
if ((!sameString("any", op)) &&
(!sameString("none", op)) &&
(!sameString("more", op)) &&
(!sameString("less", op)) &&
(!sameString("and", op)) &&
(!sameString("or", op)))
{
webAbort("Error", "Invalid value \"%s\" of CGI variable tbIntersectOp", op);
}
if (ignoreConstraints ||
((constraints2 != NULL) && (constraints2[0] == 0)))
constraints2 = NULL;
fprintf(stderr, "TBQuery: p=%s:%d-%d t1=%s q1=%s t2=%s q2=%s op=%s mT=%d lT=%d iT=%d iT2=%d\n",
chrom, winStart, winEnd,
table, constraints,
table2, constraints2,
op, moreThresh, lessThresh, invTable, invTable2);
getFullTableName(fullTableName2, chromPtr->name, table2);
if (! tableExists(fullTableName2, db2))
fbListT2 = NULL;
else if (sameString(customTrackPseudoDb, db2))
{
struct customTrack *ct2 = lookupCt(table2);
struct bedFilter *bf2 = NULL;
struct bed *bedListT2 = bedFilterListInRange(ct2->bedList, bf2,
chrom, winStart, winEnd);
struct hTableInfo *hti2 = ctToHti(ct2);
if (! ignoreConstraints)
bf2 = constrainBedFields("2");
fbListT2 = fbFromBed(track2, hti2, bedListT2, winStart, winEnd,
isBpWise, FALSE);
bedFreeList(&bedListT2);
}
else
{
char *db2 = getTable2Db();
struct hTableInfo *hti2 = getHti(db2, table2);
if (typeWiggle2)
wigMakeBedList(db2, table2, chromPtr->name, constraints2,
WIG_TABLE_2);
if ((typeWiggle2) && (bedListWig[WIG_TABLE_2] !=(struct bed *)NULL))
{
fbListT2 = fbFromBed(track2, hti2, bedListWig[WIG_TABLE_2],
winStart, winEnd, isBpWise, FALSE);
bedFreeList(&bedListWig[WIG_TABLE_2]);
}
else
fbListT2 = fbGetRangeQueryDb(db2, track2, chrom, winStart,
winEnd, constraints2, isBpWise, FALSE);
}
bitsT2 = bitAlloc(chromSize+8);
fbOrBits(bitsT2, chromSize, fbListT2, 0);
if (isBpWise)
{
// Base-pair-wise operation: get featureBits for primary table too
struct featureBits *fbListT1;
Bits *bitsT1;
fbListT1 = fbFromBed(track, hti, bedListT1, winStart, winEnd,
isBpWise, FALSE);
bitsT1 = bitAlloc(chromSize+8);
fbOrBits(bitsT1, chromSize, fbListT1, 0);
// invert inputs if necessary
if (invTable)
bitNot(bitsT1, chromSize);
if (invTable2)
bitNot(bitsT2, chromSize);
// do the intersection/union
if (sameString("and", op))
bitAnd(bitsT1, bitsT2, chromSize);
else
bitOr(bitsT1, bitsT2, chromSize);
// translate back to bed
bedListChrom = bitsToBed4List(bitsT1, chromSize, chrom, 1,
winStart, winEnd);
bitFree(&bitsT1);
featureBitsFreeList(&fbListT1);
}
else
{
for (bed = bedListT1; bed != NULL; bed = bed->next)
{
struct bed *newBed;
int numBasesOverlap = countBasesOverlap(bed, bitsT2,
hti->hasBlocks);
int length = 0;
double pctBasesOverlap;
if (hti->hasBlocks)
for (i=0; i < bed->blockCount; i++)
length += bed->blockSizes[i];
else
length = (bed->chromEnd - bed->chromStart);
if (length == 0)
length = 1;
pctBasesOverlap = ((numBasesOverlap * 100.0) / length);
if ((sameString("any", op) && (numBasesOverlap > 0)) ||
(sameString("none", op) && (numBasesOverlap == 0)) ||
(sameString("more", op) &&
(pctBasesOverlap >= moreThresh)) ||
(sameString("less", op) &&
(pctBasesOverlap <= lessThresh)))
{
newBed = cloneBed(bed);
slAddHead(&bedListChrom, newBed);
}
}
slReverse(&bedListChrom);
} // end foreach primary table bed item
bedFreeList(&bedListT1);
bitFree(&bitsT2);
featureBitsFreeList(&fbListT2);
}
else
{
/* Only one table was given, no intersection necessary. */
bedListChrom = bedListT1;
}
bedList = slCat(bedList, bedListChrom);
} // end foreach chromosome in position range
return(bedList);
}
struct slName *getAllFields()
/* Return a list of all field names in the primary table. */
{
struct slName *fieldList = NULL, *field;
char *db = getTableDb();
if (sameString(customTrackPseudoDb, db))
{
char *table = getTableName();
struct customTrack *ct = lookupCt(table);
if (ct->fieldCount >= 3)
{
field = newSlName("chrom");
slAddHead(&fieldList, field);
field = newSlName("chromStart");
slAddHead(&fieldList, field);
field = newSlName("chromEnd");
slAddHead(&fieldList, field);
}
if (ct->fieldCount >= 4)
{
field = newSlName("name");
slAddHead(&fieldList, field);
}
if (ct->fieldCount >= 5)
{
field = newSlName("score");
slAddHead(&fieldList, field);
}
if (ct->fieldCount >= 6)
{
field = newSlName("strand");
slAddHead(&fieldList, field);
}
if (ct->fieldCount >= 8)
{
field = newSlName("thickStart");
slAddHead(&fieldList, field);
field = newSlName("thickEnd");
slAddHead(&fieldList, field);
}
if (ct->fieldCount >= 9)
{
field = newSlName("itemRgb");
slAddHead(&fieldList, field);
}
if (ct->fieldCount >= 12)
{
field = newSlName("blockCount");
slAddHead(&fieldList, field);
field = newSlName("blockSizes");
slAddHead(&fieldList, field);
field = newSlName("chromStarts");
slAddHead(&fieldList, field);
}
}
else
{
struct sqlConnection *conn = hAllocOrConnect(db);
struct sqlResult *sr;
char **row;
char query[256];
snprintf(query, sizeof(query), "DESCRIBE %s", fullTableName);
sr = sqlGetResult(conn, query);
while ((row = sqlNextRow(sr)) != NULL)
{
field = newSlName(row[0]);
slAddHead(&fieldList, field);
}
sqlFreeResult(&sr);
hFreeOrDisconnect(&conn);
}
slReverse(&fieldList);
return(fieldList);
}
struct slName *getChosenFields(boolean allFields)
/* Return a list of chosen field names. */
{
struct slName *tableFields = getAllFields();
if (allFields)
{
return(tableFields);
}
else
{
struct slName *fieldList = NULL, *field;
struct cgiVar* varPtr;
for (varPtr = cgiVarList(); varPtr != NULL; varPtr = varPtr->next)
{
if (startsWith("field_", varPtr->name) &&
sameString("on", varPtr->val))
{
char *fieldStr = varPtr->name + strlen("field_");
checkIsAlpha("field name", fieldStr);
/* check that the field is there in the current table (and not
* just a stale CGI var) */
if (slNameInList(tableFields, fieldStr))
{
field = newSlName(fieldStr);
slAddHead(&fieldList, field);
}
}
}
slReverse(&fieldList);
return(fieldList);
}
}
boolean printTabbedResults(struct sqlResult *sr, boolean initialized)
{
struct hash *nameHash = newHash(18);
struct slName *wildNames = NULL, *wild=NULL;
struct hTableInfo *hti = NULL;
char *table = getTableName();
char *db = getTableDb();
char *keyStr = getUserKeys();
char *word;
char **row;
int i;
int numberColumns = sqlCountColumns(sr);
row = sqlNextRow(sr);
if (row == NULL)
return(initialized);
hti = getHti(db, table);
if (isBatch() && hti->nameField[0] != 0)
{
// last column is name (for batch filtering) -- don't print it out.
numberColumns = numberColumns - 1;
if (cgiVarExists("tbShowUploadResults"))
{
while ((word = nextWord(&keyStr)) != NULL)
{
hashAdd(nameHash, word, NULL);
}
}
else
{
while ((word = nextWord(&keyStr)) != NULL)
{
wild = slNameNew(word);
slAddHead(&wildNames, wild);
}
}
}
if (! initialized)
{
initialized = TRUE;
/* print the columns names */
printf("#");
for (i = 0; i < numberColumns; i++)
{
printf("%s\t", sqlFieldName(sr));
}
printf("\n");
}
/* print the data */
do
{
if ((! isBatch()) || (hti->nameField[0] == 0) ||
(cgiVarExists("tbShowUploadResults") &&
(hashLookup(nameHash, row[numberColumns]) != NULL)) ||
(anyWildMatch(row[numberColumns], wildNames)))
{
for (i = 0; i < numberColumns; i++)
printf("%s\t", row[i]);
printf("\n");
}
}
while((row = sqlNextRow(sr)) != NULL);
return(initialized);
}
boolean printTabbedBed(struct bed *bedList, struct slName *chosenFields,
boolean initialized)
/* Print out the chosen fields of a bedList. */
{
struct bed *bed;
struct slName *field;
if (bedList == NULL)
return(initialized);
if (! initialized)
{
boolean gotFirst = FALSE;
initialized = TRUE;
printf("#");
for (field=chosenFields; field != NULL; field=field->next)
{
if (! gotFirst)
gotFirst = TRUE;
else
printf("\t");
printf("%s", field->name);
}
printf("\n");
}
for (bed=bedList; bed != NULL; bed=bed->next)
{
boolean gotFirst = FALSE;
for (field=chosenFields; field != NULL; field=field->next)
{
if (! gotFirst)
gotFirst = TRUE;
else
printf("\t");
if (sameString(field->name, "chrom"))
printf("%s", bed->chrom);
else if (sameString(field->name, "chromStart"))
printf("%d", bed->chromStart);
else if (sameString(field->name, "chromEnd"))
printf("%d", bed->chromEnd);
else if (sameString(field->name, "name"))
printf("%s", bed->name);
else if (sameString(field->name, "score"))
printf("%d", bed->score);
else if (sameString(field->name, "strand"))
printf("%s", bed->strand);
else if (sameString(field->name, "thickStart"))
printf("%d", bed->thickStart);
else if (sameString(field->name, "thickEnd"))
printf("%d", bed->thickEnd);
else if (sameString(field->name, "itemRgb"))
printf("%d", bed->itemRgb);
else if (sameString(field->name, "blockCount"))
printf("%d", bed->blockCount);
else if (sameString(field->name, "blockSizes"))
{
int i;
for (i=0; i < bed->blockCount; i++)
printf("%d,", bed->blockSizes[i]);
}
else if (sameString(field->name, "chromStarts"))
{
int i;
for (i=0; i < bed->blockCount; i++)
printf("%d,", bed->chromStarts[i]);
}
else
errAbort("\nUnrecognized bed field name \"%s\"", field->name);
}
printf("\n");
}
return(initialized);
}
void showTdbInfo(struct trackDb *tdb)
/* Show interesting stuff from tdb. */
{
if (tdb != NULL)
{
puts(" ");
printf("Track information for %s (%s): \n",
tdb->shortLabel, tdb->longLabel);
printf("Track type: %s \n", tdb->type);
if (tdb->settings != NULL && tdb->settings[0] != 0)
printf("Additional settings: %s \n", tdb->settings);
printf("Track group: %s \n", tdb->grp);
if (tdb->url != NULL && tdb->url[0] != 0)
printf("Feature URL: %s \n", tdb->url);
if (tdb->html != NULL && tdb->html[0] != 0)
puts(tdb->html);
}
}
void describeCustomTrack (char *ctName)
/* Describe the contents of a custom track as well as we can. */
{
char *db = getTableDb();
char *table = getTableName();
struct hTableInfo *hti = getHti(db, table);
struct customTrack *ct = lookupCt(table);
struct bed *firstFewBed = NULL, *bed = NULL;
int i;
printf(" Custom track %s is stored locally as a bed %d file.\n",
table, ct->fieldCount);
puts("(Note: custom tracks may initially be loaded into the browser \n"
"from files in other formats such as PSL or GFF, \n"
"but upon loading they are translated to BED for local processing \n"
"and temporary storage.)");
printf("
Custom track %s has %d rows total. \n",
hti->rootName, slCount(ct->bedList));
if (ct->bedList != 0)
{
firstFewBed = NULL;
for (i=0,bed=ct->bedList; i < 3 && bed != NULL; i++,bed=bed->next)
{
struct bed *newBed = cloneBed(bed);
slAddHead(&firstFewBed, newBed);
}
slReverse(&firstFewBed);
printf ("Example rows of custom track %s (not necessarily from current position!): \n",
hti->rootName);
puts("");
printTabbedBed(firstFewBed, getChosenFields(TRUE), FALSE);
puts(" ");
}
showTdbInfo(ct->tdb);
if (browserLines != NULL)
{
struct slName *l = NULL;
puts("
Custom track browser lines: ");
puts("");
for (l = browserLines; l != NULL; l = l->next)
{
puts(l->name);
}
puts(" ");
puts("");
}
}
boolean showTableDescriptions(struct sqlConnection *conn, char *table)
/* Display autoSql definition and gbdDescriptions link for table,
* if available. */
{
boolean gotInfo = FALSE;
static char *asTableName = "tableDescriptions";
if (sqlTableExists(conn, asTableName))
{
struct sqlResult *sr = NULL;
struct tableDescriptions *asi = NULL;
char query[512];
char **row = NULL;
safef(query, sizeof(query), "select * from %s where tableName = '%s'",
asTableName, table);
sr = sqlGetResult(conn, query);
if ((row = sqlNextRow(sr)) != NULL)
{
asi = tableDescriptionsLoad(row);
gotInfo = TRUE;
if (asi->autoSqlDef != NULL && asi->autoSqlDef[0] != 0)
{
puts("
\n", table);
puts("");
puts(asi->autoSqlDef);
puts(" ");
}
if (asi->gbdAnchor != NULL && asi->gbdAnchor[0] != 0)
{
puts("");
printf("",
asi->gbdAnchor);
printf("Genome Browser Database Description for %s ", table);
}
}
sqlFreeResult(&sr);
}
return(gotInfo);
}
void showItemCountFirstFew(struct sqlConnection *conn, int n)
/* Show the item count and first n items of table. */
{
char *track = getTrackName();
struct slName *tableList = hSplitTableNames(track);
struct slName *tPtr = NULL;
struct sqlResult *sr = NULL;
struct dyString *query = newDyString(256);
char **row = NULL;
char *table = getTableName();
int count = 0;
int numberColumns = 0;
int i = 0;
#define NEEDED_UNTIL_GB_CDNA_INFO_CHANGE
#ifdef NEEDED_UNTIL_GB_CDNA_INFO_CHANGE
if (sameString(table, "mrna"))
{
struct slName *slNew = newSlName(table);
slFreeList(&tableList);
tableList = slNew;
}
#endif /* NEEDED_UNTIL_GB_CDNA_INFO_CHANGE */
for (tPtr=tableList; tPtr != NULL; tPtr=tPtr->next)
{
count += sqlTableSize(conn, tPtr->name);
}
printf("
Table %s has %d rows total. \n", table, count);
if (count > 0)
{
dyStringPrintf(query, "select * from %s limit %d", tableList->name, n);
sr = sqlGetResult(conn, query->string);
printf ("Example rows of table %s (not necessarily from current position!): \n",
table);
puts("");
numberColumns = sqlCountColumns(sr);
printf("#");
for (i = 0; i < numberColumns; i++)
{
printf("%s\t", sqlFieldName(sr));
}
printf("\n");
while ((row = sqlNextRow(sr)) != NULL)
{
for (i = 0; i < numberColumns; i++)
printf("%s\t", row[i]);
printf("\n");
}
puts("
");
}
}
void descTable(boolean histButtons)
/* Print out an HTML table showing table fields and types, and optionally
* offering histograms for the text/enum fields. */
{
char *db = getTableDb();
struct sqlConnection *conn = hAllocOrConnect(db);
struct sqlResult *sr;
char **row;
boolean tooBig = (sqlTableSize(conn, fullTableName) > TOO_BIG_FOR_HISTO);
char button[64];
char query[256];
safef(query, sizeof(query), "desc %s", fullTableName);
sr = sqlGetResult(conn, query);
// For some reason BORDER=1 does not work in our web.c nested table scheme.
// So use web.c's trick of using an enclosing table to provide a border.
puts("" "\n"
- "
");
-puts("");
+ "");
+puts("");
printf(" name SQL type ");
histButtons = (histButtons && ! tooBig);
if (histButtons)
printf("text value histogram ");
puts(" ");
while ((row = sqlNextRow(sr)) != NULL)
{
printf(" %s %s ", row[0], row[1]);
if (histButtons)
{
printf(" ");
if ((isSqlStringType(row[1]) || startsWith("enum", row[1])) &&
! sameString(row[1], "longblob"))
{
snprintf(button, sizeof(button), "%s for %s",histPhase,row[0]);
cgiMakeButton("phase", button);
}
else
{
printf(" ");
}
printf(" ");
}
puts(" ");
}
puts("
");
puts("
");
sqlFreeResult(&sr);
hFreeOrDisconnect(&conn);
}
void doDescTable ()
/* Describe the contents of the primary table/custom track as well as we can. */
{
char *table = getTableName();
char *db = getTableDb();
saveChooseTableState();
webStart(cart, "Table Browser: %s %s: %s %s.%s",
hOrganism(database), freezeName, descTablePhase, db, table);
checkTableExists(fullTableName);
printf("\n\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiMakeHiddenVar("table", getTableVar());
displayPosition();
puts(""
"Help ");
puts("
");
cgiMakeButton("phase", oldAllFieldsPhase);
cgiMakeButton("phase", oldSeqOptionsPhase);
cgiMakeButton("phase", outputOptionsPhase);
if (tableIsPositional)
explainCoordSystem();
if (sameString(customTrackPseudoDb, db))
describeCustomTrack(table);
else
{
struct sqlConnection *conn = hAllocOrConnect(db);
char *track = getTrackName();
showTableDescriptions(conn, table);
printf(" Fields of %s: \n", table);
descTable(TRUE);
showItemCountFirstFew(conn, 3);
// "show table status" is a SLOW query (~30s!), but it would be kinda cool
// to tell the creation & last-update dates and times.
if (tableIsPositional && sqlTableExists(conn, hTrackDbName()))
{
struct trackDb *tdb;
tdb = hMaybeTrackInfo(conn, track);
if (tdb)
showTdbInfo(tdb);
}
hFreeOrDisconnect(&conn);
}
puts("");
cgiMakeButton("phase", oldAllFieldsPhase);
cgiMakeButton("phase", oldSeqOptionsPhase);
cgiMakeButton("phase", outputOptionsPhase);
printf("
\n");
webEnd();
}
void doTabSeparatedCT(boolean allFields)
{
struct bed *bedList;
char *table = getTableName();
struct customTrack *ct = lookupCt(table);
struct slName *chosenFields;
struct bedFilter *bf;
boolean gotResults;
printf("Content-Type: text/plain\n\n");
webStartText();
checkTableExists(fullTableName);
bf = constrainBedFields(NULL);
chosenFields = getChosenFields(allFields);
if (chosenFields == NULL)
{
printf("\n# Error: at least one field must be selected.\n\n");
return;
}
if (allGenome)
bedList = cloneBedList(ct->bedList);
else
bedList = bedFilterListInRange(ct->bedList, bf, chrom, winStart, winEnd);
bedFilterBatch(&bedList);
gotResults = printTabbedBed(bedList, chosenFields, FALSE);
bedFreeList(&bedList);
if (! gotResults)
printf("\n# No results returned from query.\n\n");
}
void doTabSeparated(boolean allFields)
{
struct slName *chromList, *chromPtr;
struct sqlConnection *conn;
struct sqlResult *sr;
struct dyString *query = newDyString(512);
struct dyString *fieldSpec = newDyString(256);
struct hTableInfo *hti = NULL;
char *table = getTableName();
char *db = getTableDb();
char *constraints;
boolean gotResults;
checkUserKeys();
saveChooseTableState();
saveChooseFieldsState();
saveOutputOptionsState();
saveIntersectOptionsState();
if (sameString(customTrackPseudoDb, db))
{
doTabSeparatedCT(allFields);
return;
}
printf("Content-Type: text/plain\n\n");
webStartText();
checkTableExists(fullTableName);
hti = getHti(db, table);
constraints = constrainFields(NULL);
if (allGenome)
chromList = hAllChromNames();
else
chromList = newSlName(chrom);
dyStringClear(fieldSpec);
if (allFields)
dyStringAppend(fieldSpec, "*");
else
{
struct slName *chosenFields = getChosenFields(allFields);
struct slName *field;
boolean gotFirst = FALSE;
if (chosenFields == NULL)
{
printf("\n# Error: at least one field must be selected.\n\n");
return;
}
for (field=chosenFields; field != NULL; field=field->next)
{
if (! gotFirst)
gotFirst = TRUE;
else
dyStringAppend(fieldSpec, ",");
dyStringAppend(fieldSpec, field->name);
}
}
if (isBatch() && hti->nameField[0] != 0)
{
dyStringAppend(fieldSpec, ",");
dyStringAppend(fieldSpec, hti->nameField);
}
conn = hAllocOrConnect(db);
gotResults = FALSE;
if (tableIsSplit)
{
for (chromPtr=chromList; chromPtr != NULL; chromPtr = chromPtr->next)
{
getFullTableName(fullTableName, chromPtr->name, table);
if (! sqlTableExists(conn, fullTableName))
continue;
dyStringClear(query);
dyStringPrintf(query, "SELECT %s FROM %s",
fieldSpec->string, fullTableName);
if ((! allGenome) && tableIsPositional)
{
dyStringPrintf(query, " WHERE %s < %d AND %s > %d",
hti->startField, winEnd, hti->endField, winStart);
if ((constraints != NULL) && (constraints[0] != 0))
dyStringPrintf(query, " AND %s", constraints);
}
else if ((constraints != NULL) && (constraints[0] != 0))
dyStringPrintf(query, " WHERE %s", constraints);
sr = sqlGetResult(conn, query->string);
gotResults = printTabbedResults(sr, gotResults);
sqlFreeResult(&sr);
}
}
else
{
dyStringClear(query);
dyStringPrintf(query, "SELECT %s FROM %s",
fieldSpec->string, fullTableName);
if ((! allGenome) && tableIsPositional)
{
dyStringPrintf(query, " WHERE %s < %d AND %s > %d",
hti->startField, winEnd, hti->endField, winStart);
if (! sameString("", hti->chromField))
dyStringPrintf(query, " AND %s = \'%s\'",
hti->chromField, chrom);
if ((constraints != NULL) && (constraints[0] != 0))
dyStringPrintf(query, " AND %s", constraints);
}
else if ((constraints != NULL) && (constraints[0] != 0))
dyStringPrintf(query, " WHERE %s", constraints);
sr = sqlGetResult(conn, query->string);
gotResults = printTabbedResults(sr, gotResults);
sqlFreeResult(&sr);
}
if (! gotResults)
printf("\n# No results returned from query.\n\n");
dyStringFree(&query);
hFreeOrDisconnect(&conn);
}
void doChooseFields()
{
struct slName *allFields = getAllFields();
struct slName *field;
char *table = getTableName();
char *db = getTableDb();
char *outputType = cgiUsualString("outputType", cgiString("phase"));
char name[128];
boolean checkAll;
boolean clearAll;
saveOutputOptionsState();
saveIntersectOptionsState();
webStart(cart, "Table Browser: %s %s: Choose Fields of %s", hOrganism(database),freezeName, table);
checkTableExists(fullTableName);
printf("\n\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiMakeHiddenVar("table", getTableVar());
displayPosition();
cgiMakeHiddenVar("outputType", outputType);
preserveConstraints(fullTableName, db, NULL);
preserveTable2();
printf(" Select Fields of %s: \n", getTableName());
puts(""
"Help ");
cgiMakeHiddenVar("origPhase", cgiString("phase"));
cgiMakeButton("submit", "Check All");
cgiMakeButton("submit", "Clear All");
checkAll = existsAndEqual("submit", "Check All") ? TRUE : FALSE;
clearAll = existsAndEqual("submit", "Clear All") ? TRUE : FALSE;
puts("
");
for (field=allFields; field != NULL; field=field->next)
{
boolean fieldChecked;
puts("");
snprintf(name, sizeof(name), "field_%s", field->name);
fieldChecked = cartCgiUsualBoolean(cart, name, FALSE);
cgiMakeCheckBox(name,
(checkAll || (fieldChecked && !clearAll)));
puts(field->name);
puts(" ");
}
puts("
\n");
cgiMakeButton("phase", getSomeFieldsPhase);
puts(" ");
webEnd();
}
void doSequenceOptions()
{
struct hTableInfo *hti = getOutputHti();
char *outputType = cgiUsualString("outputType", cgiString("phase"));
saveChooseTableState();
saveOutputOptionsState();
saveIntersectOptionsState();
if (! tableIsPositional)
webAbort("Table must be positional",
"Sorry, can't get sequence for items from a non-positional table. "
"Please go back and select a browser track or positional table.");
webStart(cart, "Table Browser: %s %s: %s", hOrganism(database),freezeName, seqOptionsPhase);
checkTableExists(fullTableName);
printf("\n\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiMakeHiddenVar("table", getTableVar());
displayPosition();
cgiMakeHiddenVar("outputType", outputType);
preserveConstraints(fullTableName, getTableDb(), NULL);
preserveTable2();
printf("Table: %s \n", hti->rootName);
puts(""
"Help ");
hgSeqOptionsHtiCart(hti, cart);
cgiMakeButton("phase", getSequencePhase);
puts("
");
webEnd();
}
void doGetSequence()
/* Display FASTA sequence. */
{
struct hTableInfo *hti = getOutputHti();
struct bed *bedList;
int itemCount;
saveOutputOptionsState();
saveIntersectOptionsState();
saveSequenceOptionsState();
printf("Content-Type: text/plain\n\n");
webStartText();
bedList = getBedList(FALSE, NULL);
itemCount = hgSeqBedDb(database, hti, bedList);
bedFreeList(&bedList);
if (itemCount == 0)
printf("\n# No results returned from query.\n\n");
}
static void addGffLineFromBed(struct gffLine **pGffList, struct bed *bed,
char *source, char *feature,
int start, int end, char frame, char *txName)
/* Create a gffLine from a bed and line-specific parameters, add to list. */
{
struct gffLine *gff;
AllocVar(gff);
gff->seq = cloneString(bed->chrom);
gff->source = cloneString(source);
gff->feature = cloneString(feature);
gff->start = start;
gff->end = end;
gff->score = bed->score;
gff->strand = bed->strand[0];
gff->frame = frame;
gff->group = cloneString(txName);
if (bed->name)
gff->geneId = cloneString(bed->name);
else
{
char name[64];
safef(name, sizeof(name), "%s.%d", bed->chrom, bed->chromStart);
gff->geneId = cloneString(name);
}
slAddHead(pGffList, gff);
}
static void addCdsStartStop(struct gffLine **pGffList, struct bed *bed,
char *source, int s, int e, char *frames,
int i, int startIndx, int stopIndx,
boolean gtf2StopCodons, char *txName)
{
// start_codon (goes first for + strand) overlaps with CDS
if ((i == startIndx) && (bed->strand[0] != '-'))
{
addGffLineFromBed(pGffList, bed, source, "start_codon",
s, s+3, '.', txName);
}
// stop codon does not overlap with CDS as of GTF2
if ((i == stopIndx) && gtf2StopCodons)
{
if (bed->strand[0] == '-')
{
addGffLineFromBed(pGffList, bed, source, "stop_codon",
s, s+3, '.', txName);
addGffLineFromBed(pGffList, bed, source, "CDS", s+3, e,
frames[i], txName);
}
else
{
addGffLineFromBed(pGffList, bed, source, "CDS", s, e-3,
frames[i], txName);
addGffLineFromBed(pGffList, bed, source, "stop_codon",
e-3, e, '.', txName);
}
}
else
{
addGffLineFromBed(pGffList, bed, source, "CDS", s, e,
frames[i], txName);
}
// start_codon (goes last for - strand) overlaps with CDS
if ((i == startIndx) && (bed->strand[0] == '-'))
{
addGffLineFromBed(pGffList, bed, source, "start_codon",
e-3, e, '.', txName);
}
}
struct gffLine *bedToGffLines(struct bed *bedList, struct hTableInfo *hti,
char *source, boolean gtf2StopCodons)
/* Translate a (list of) bed into list of gffLine elements. */
{
struct hash *nameHash = newHash(20);
struct gffLine *gffList = NULL;
struct bed *bed;
int i, j, s, e;
char txName[256];
for (bed = bedList; bed != NULL; bed = bed->next)
{
/* Enforce unique transcript_ids. */
char name[64];
struct hashEl *hel = NULL;
int dupCount = 0;
if (bed->name)
hel = hashLookup(nameHash, bed->name);
else
{
safef(name, sizeof(name), "%s.%d", bed->chrom, bed->chromStart);
hel = hashLookup(nameHash, name);
}
dupCount = (hel != NULL ? ptToInt(hel->val) : 0);
if (dupCount > 0)
{
safef(txName, sizeof(txName), "%s_dup%d", bed->name, dupCount);
hel->val = intToPt(dupCount + 1);
}
else
{
if (bed->name)
{
safef(txName, sizeof(txName), "%s", bed->name);
hashAddInt(nameHash, bed->name, 1);
}
else
{
safef(txName, sizeof(txName), "%s", name);
hashAddInt(nameHash, name, 1);
}
}
if (hti->hasBlocks && hti->hasCDS)
{
char *frames = needMem(bed->blockCount);
boolean gotFirstCds = FALSE;
int nextPhase = 0;
int startIndx = 0;
int stopIndx = 0;
/* first pass: compute frames, in order dictated by strand. */
for (i=0; i < bed->blockCount; i++)
{
if (bed->strand[0] == '-')
j = bed->blockCount-i-1;
else
j = i;
s = bed->chromStart + bed->chromStarts[j];
e = s + bed->blockSizes[j];
if ((s < bed->thickEnd) && (e > bed->thickStart))
{
int cdsSize = e - s;
if (e > bed->thickEnd)
cdsSize = bed->thickEnd - s;
else if (s < bed->thickStart)
cdsSize = e - bed->thickStart;
if (! gotFirstCds)
{
gotFirstCds = TRUE;
startIndx = j;
}
frames[j] = '0' + nextPhase;
nextPhase = (3 + ((nextPhase - cdsSize) % 3)) % 3;
stopIndx = j;
}
else
{
frames[j] = '.';
}
}
/* second pass: one exon (possibly CDS, start/stop_codon) per block. */
for (i=0; i < bed->blockCount; i++)
{
s = bed->chromStart + bed->chromStarts[i];
e = s + bed->blockSizes[i];
if ((s >= bed->thickStart) && (e <= bed->thickEnd))
{
addCdsStartStop(&gffList, bed, source, s, e, frames,
i, startIndx, stopIndx, gtf2StopCodons,
txName);
}
else if ((s < bed->thickStart) && (e > bed->thickEnd))
{
addCdsStartStop(&gffList, bed, source,
bed->thickStart, bed->thickEnd,
frames, i, startIndx, stopIndx,
gtf2StopCodons, txName);
}
else if ((s < bed->thickStart) && (e > bed->thickStart))
{
addCdsStartStop(&gffList, bed, source, bed->thickStart, e,
frames, i, startIndx, stopIndx,
gtf2StopCodons, txName);
}
else if ((s < bed->thickEnd) && (e > bed->thickEnd))
{
addCdsStartStop(&gffList, bed, source, s, bed->thickEnd,
frames, i, startIndx, stopIndx,
gtf2StopCodons, txName);
}
addGffLineFromBed(&gffList, bed, source, "exon", s, e, '.',
txName);
}
freeMem(frames);
}
else if (hti->hasBlocks)
{
for (i=0; i < bed->blockCount; i++)
{
s = bed->chromStart + bed->chromStarts[i];
e = s + bed->blockSizes[i];
addGffLineFromBed(&gffList, bed, source, "exon", s, e, '.',
txName);
}
}
else if (hti->hasCDS)
{
if (bed->thickStart > bed->chromStart)
{
addGffLineFromBed(&gffList, bed, source, "exon", bed->chromStart,
bed->thickStart, '.', txName);
}
addGffLineFromBed(&gffList, bed, source, "CDS", bed->thickStart,
bed->thickEnd, '0', txName);
if (bed->thickEnd < bed->chromEnd)
{
addGffLineFromBed(&gffList, bed, source, "exon", bed->thickEnd,
bed->chromEnd, '.', txName);
}
}
else
{
addGffLineFromBed(&gffList, bed, source, "exon", bed->chromStart,
bed->chromEnd, '.', txName);
}
}
slReverse(&gffList);
hashFree(&nameHash);
return(gffList);
}
void doGetGFF()
{
struct hTableInfo *hti = getOutputHti();
struct bed *bedList;
struct gffLine *gffList, *gffPtr;
char source[64];
char *db = getTableDb();
char *track = getTrackName();
int itemCount;
// Would be nice to allow user to select this, but I don't want to
// make an options page for just one param... any others?
// ? exon / CDS ?
boolean gtf2StopCodons = FALSE;
saveOutputOptionsState();
saveIntersectOptionsState();
printf("Content-Type: text/plain\n\n");
webStartText();
bedList = getBedList(FALSE, NULL);
if (sameString(customTrackPseudoDb, db))
snprintf(source, sizeof(source), "%s", track);
else
snprintf(source, sizeof(source), "%s_%s", db, track);
itemCount = 0;
gffList = bedToGffLines(bedList, hti, source, gtf2StopCodons);
bedFreeList(&bedList);
for (gffPtr = gffList; gffPtr != NULL; gffPtr = gffPtr->next)
{
gffTabOut(gffPtr, stdout);
itemCount++;
}
slFreeList(&gffList);
if (itemCount == 0)
printf("\n# No results returned from query.\n\n");
}
void doBedCtOptions(boolean doCt)
{
struct hTableInfo *hti = getOutputHti();
char *table = getTableName();
char *table2 = getTable2Name();
char *op = cgiOptionalString("tbIntersectOp");
char *db = getTableDb();
char *outputType = cgiUsualString("outputType", cgiString("phase"));
char *phase = (existsAndEqual("phase", getOutputPhase) ?
cgiString("outputType") : cgiString("phase"));
char *setting = NULL;
char buf[256];
saveOutputOptionsState();
saveIntersectOptionsState();
webStart(cart, "Table Browser: %s %s: %s", hOrganism(database), freezeName,
phase);
checkTableExists(fullTableName);
printf("\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiMakeHiddenVar("table", getTableVar());
displayPosition();
cgiMakeHiddenVar("outputType", outputType);
preserveConstraints(fullTableName, db, NULL);
preserveTable2();
printf(" Select %s Options for %s: \n",
(doCt ? "Custom Track" : "BED"), hti->rootName);
puts(""
"Help ");
puts("
");
if (doCt)
{
puts(" "
""
"Custom track header: ");
}
else
{
cgiMakeCheckBox("tbDoCustomTrack",
cartCgiUsualBoolean(cart, "tbDoCustomTrack", FALSE));
puts(" Include "
""
"custom track header: ");
}
puts(" name=");
if (op == NULL)
table2 = NULL;
snprintf(buf, sizeof(buf), "tb_%s", hti->rootName);
setting = cgiUsualString("tbCtName", buf);
cgiMakeTextVar("tbCtName", setting, 16);
puts(" description=");
snprintf(buf, sizeof(buf), "table browser query on %s%s%s",
table,
(table2 ? ", " : ""),
(table2 ? table2 : ""));
setting = cgiUsualString("tbCtDesc", buf);
cgiMakeTextVar("tbCtDesc", setting, 50);
puts(" visibility=");
setting = cartCgiUsualString(cart, "tbCtVis", ctVisMenu[3]);
cgiMakeDropList("tbCtVis", ctVisMenu, ctVisMenuSize, setting);
puts(" url=");
setting = cartCgiUsualString(cart, "tbCtUrl", "");
cgiMakeTextVar("tbCtUrl", setting, 50);
puts(" ");
puts("
");
puts(" Create one BED record per: ");
fbOptionsHtiCart(hti, cart);
if (doCt)
{
cgiMakeButton("phase", getCtPhase);
cgiMakeButton("phase", getCtBedPhase);
}
else
{
cgiMakeButton("phase", getBedPhase);
}
puts("
");
webEnd();
}
struct customTrack *newCT(char *ctName, char *ctDesc, int visNum, char *ctUrl,
int fields)
/* Make a new custom track record for the query results. */
{
struct customTrack *ct;
struct trackDb *tdb;
char buf[256];
AllocVar(ct);
AllocVar(tdb);
snprintf(buf, sizeof(buf), "ct_%s", ctName);
tdb->tableName = cloneString(buf);
tdb->shortLabel = ctName;
tdb->longLabel = ctDesc;
snprintf(buf, sizeof(buf), "bed %d .", fields);
tdb->type = cloneString(buf);
tdb->visibility = visNum;
tdb->url = ctUrl;
ct->tdb = tdb;
ct->fieldCount = fields;
ct->needsLift = FALSE;
ct->fromPsl = FALSE;
ct->wiggle = FALSE;
ct->wigAscii = (char *)NULL;
ct->wigFile = (char *)NULL;
ct->wibFile = (char *)NULL;
return(ct);
}
void doGetBedCt(boolean doCt)
{
struct hTableInfo *hti = getOutputHti();
struct bed *bedList;
struct bed *bedPtr;
struct featureBits *fbList = NULL, *fbPtr;
struct customTrack *ctNew = NULL;
char *table = getTableName();
char *phase = (existsAndEqual("phase", getOutputPhase) ?
cgiString("outputType") : cgiString("phase"));
boolean doCtHdr = (cgiBoolean("tbDoCustomTrack") || doCt ||
sameString(phase, getCtBedPhase));
char *ctName = cgiUsualString("tbCtName", table);
char *ctDesc = cgiUsualString("tbCtDesc", table);
char *ctVis = cgiUsualString("tbCtVis", "dense");
char *ctUrl = cgiUsualString("tbCtUrl", "");
char *fbQual = fbOptionsToQualifier();
char fbTQ[128];
int fields;
boolean gotResults = FALSE;
saveOutputOptionsState();
saveIntersectOptionsState();
saveBedCtOptionsState();
if (! doCt)
{
printf("Content-Type: text/plain\n\n");
webStartText();
}
bedList = getBedList(FALSE, NULL);
fields = hTableInfoBedFieldCount(hti);
if (doCtHdr && (bedList != NULL))
{
int visNum = (int) hTvFromStringNoAbort(ctVis);
if (visNum < 0)
visNum = 0;
if (doCt)
ctNew = newCT(ctName, ctDesc, visNum, ctUrl, fields);
else
printf("track name=\"%s\" description=\"%s\" visibility=%d url=%s \n",
ctName, ctDesc, visNum, ctUrl);
}
if ((fbQual == NULL) || (fbQual[0] == 0))
{
for (bedPtr = bedList; bedPtr != NULL; bedPtr = bedPtr->next)
{
char *ptr = NULL;
if (bedPtr->name)
ptr = strchr(bedPtr->name, ' ');
if (ptr != NULL)
*ptr = 0;
if (! doCt)
{
bedTabOutN(bedPtr, fields, stdout);
}
gotResults = TRUE;
}
if (ctNew != NULL)
ctNew->bedList = bedList;
}
else
{
snprintf(fbTQ, sizeof(fbTQ), "%s:%s", hti->rootName, fbQual);
fbList = fbFromBed(fbTQ, hti, bedList, winStart, winEnd, FALSE, FALSE);
for (fbPtr=fbList; fbPtr != NULL; fbPtr=fbPtr->next)
{
char *ptr = strchr(fbPtr->name, ' ');
if (ptr != NULL)
*ptr = 0;
if (! doCt)
{
printf("%s\t%d\t%d\t%s\t%d\t%c\n",
fbPtr->chrom, fbPtr->start, fbPtr->end, fbPtr->name,
0, fbPtr->strand);
}
gotResults = TRUE;
}
if (ctNew != NULL)
ctNew->bedList = fbToBed(fbList);
featureBitsFreeList(&fbList);
}
if ((ctNew != NULL) && (ctNew->bedList != NULL))
{
/* Load existing custom tracks and add this new one: */
struct customTrack *ctList = getCustomTracks();
slAddHead(&ctList, ctNew);
/* Save the custom tracks out to file (overwrite the old file): */
customTracksSaveCart(cart, ctList);
}
if (! gotResults)
{
printf("\n# No results returned from query.\n\n");
}
else if (doCt)
{
char browserUrl[256];
char headerText[512];
int redirDelay = 5;
char *newChrom = chrom;
int newStart = winStart, newEnd = winEnd;
if (allGenome)
{
newChrom = ctNew->bedList->chrom;
newStart = ctNew->bedList->chromStart;
newEnd = ctNew->bedList->chromEnd;
}
safef(browserUrl, sizeof(browserUrl),
"%s?db=%s&position=%s:%d-%d",
hgTracksName(), database, newChrom, newStart, newEnd);
safef(headerText, sizeof(headerText),
" ",
redirDelay, browserUrl);
webStartHeader(cart, headerText,
"Table Browser: %s %s: %s", hOrganism(database),
freezeName, getCtPhase);
printf("You will be automatically redirected to the genome browser in\n"
"%d seconds, or you can \n"
"click here to continue .\n",
redirDelay, browserUrl);
}
bedFreeList(&bedList);
} /* void doGetBedCt(boolean doCt) */
void doGetBrowserLinks()
{
struct bed *bedList;
struct bed *bedPtr;
char *track = getTrackName();
char *track2 = getTrack2Name();
char track2CGI[128];
char posBuf[64];
int itemCount;
saveOutputOptionsState();
saveIntersectOptionsState();
webStart(cart, "Table Browser: %s %s: %s", hOrganism(database),freezeName, linksPhase);
bedList = getBedList(FALSE, NULL);
printf(" Links to Genome Browser from %s \n", getTableName());
puts(""
"Help ");
if ((track2 != NULL) && (track2[0] != 0))
safef(track2CGI, sizeof(track2CGI), "&%s=%s", track2,
hTrackOpenVis(track2));
else
track2CGI[0] = 0;
itemCount = 0;
for (bedPtr = bedList; bedPtr != NULL; bedPtr = bedPtr->next)
{
printf("chrom, bedPtr->chromStart+1,
bedPtr->chromEnd, track, hTrackOpenVis(track), track2CGI,
cartSessionId(cart));
snprintf(posBuf, sizeof(posBuf), "%s:%d-%d", bedPtr->chrom,
bedPtr->chromStart+1, bedPtr->chromEnd);
if (bedPtr->name && sameString(bedPtr->name, posBuf))
printf(" TARGET=_blank> %s \n", posBuf);
else if (bedPtr->name)
printf(" TARGET=_blank> %s %s \n", bedPtr->name, posBuf);
else
printf(" TARGET=_blank> %s \n", posBuf);
itemCount++;
}
bedFreeList(&bedList);
if (itemCount == 0)
puts("No results returned from query.");
webEnd();
}
void doIntersectOptions()
{
char *outputType = cgiString("outputType");
char *table = getTableName();
char *table2 = getTable2Name();
char *db = getTableDb();
char *db2 = getTable2Db();
char *setting, *op;
char fullTableName2[256];
struct hTableInfo *hti = NULL;
saveOutputOptionsState();
webStart(cart, "Table Browser: %s %s: %s", hOrganism(database),freezeName, intersectOptionsPhase);
checkTableExists(fullTableName);
if (table2 == NULL)
webAbort("Missing table selection",
"Please choose a table and try again.");
getFullTableName(fullTableName2, chrom, table2);
checkTable2Exists(fullTableName2);
if (! tableIsPositional)
webAbort("Error", "Table %s is not a positional table.", table);
if (! sameString(outputType, seqOptionsPhase) &&
! sameString(outputType, bedOptionsPhase) &&
! sameString(outputType, ctOptionsPhase) &&
! sameString(outputType, linksPhase) &&
! sameString(outputType, statsPhase) &&
! sameString(outputType, gffPhase))
webAbort("Error", "Please choose one of the supported output formats "
"(FASTA, BED, HyperLinks, GTF or Summary/Statistics) for "
"intersection of tables.");
hti = getHti(db2, table2);
typeWiggle2 = isWiggle(db2, table2);
printf("\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiMakeHiddenVar("table", getTableVar());
displayPosition();
cgiMakeHiddenVar("outputType", outputType);
cgiMakeHiddenVar("table2", getTable2Var());
preserveConstraints(fullTableName, db, NULL);
preserveConstraints(fullTableName2, db2, "2");
printf(" Specify how to combine tables %s and %s: \n",
table, table2);
puts(""
"Help ");
printf("These combinations will maintain the gene/alignment structure (if any) of %s:
\n",
table);
op = cartCgiUsualString(cart, "tbIntersectOp", "any");
cgiMakeRadioButton("tbIntersectOp", "any", sameString(op, "any"));
printf("All %s records that have any overlap with %s
\n",
table, table2);
cgiMakeRadioButton("tbIntersectOp", "none", sameString(op, "none"));
printf("All %s records that have no overlap with %s
\n",
table, table2);
cgiMakeRadioButton("tbIntersectOp", "more", sameString(op, "more"));
printf("All %s records that have at least ",
table);
setting = cartCgiUsualString(cart, "tbMoreThresh", "80");
cgiMakeTextVar("tbMoreThresh", setting, 3);
printf(" %% overlap with %s
\n", table2);
cgiMakeRadioButton("tbIntersectOp", "less", sameString(op, "less"));
printf("All %s records that have at most ",
table);
setting = cartCgiUsualString(cart, "tbLessThresh", "80");
cgiMakeTextVar("tbLessThresh", setting, 3);
printf(" %% overlap with %s
\n", table2);
printf("These combinations will discard the gene/alignment structure (if any) of %s and produce a simple list of position ranges.\n",
table);
puts("To complement a table means to consider a position included if it \n"
"is not included in the table.
");
cgiMakeRadioButton("tbIntersectOp", "and", sameString(op, "and"));
printf("Base-pair-wise intersection (AND) of %s and %s
\n",
table, table2);
cgiMakeRadioButton("tbIntersectOp", "or", sameString(op, "or"));
printf("Base-pair-wise union (OR) of %s and %s
\n",
table, table2);
cgiMakeCheckBox("tbInvertTable", cgiBoolean("tbInvertTable"));
printf("Complement %s before intersection/union
\n", table);
cgiMakeCheckBox("tbInvertTable2", cgiBoolean("tbInvertTable2"));
printf("Complement %s before intersection/union
\n", table2);
cgiMakeButton("phase", outputType);
printf("
(Optional) Filter %s Records by Field Values \n",
table2);
puts(""
"Help ");
if (sameString(customTrackPseudoDb, db2))
filterOptionsCustomTrack(table2, "2");
else
filterOptionsTableDb(fullTableName2, db2, "2", typeWiggle2);
cgiMakeButton("phase", outputType);
puts("
");
webEnd();
}
void descForm()
/* Print out an HTML FORM showing table fields and types, and offering
* histograms for the text/enum fields. */
{
char *db = getTableDb();
// Not supported for custom tracks, just for database tables.
if (sameString(customTrackPseudoDb, db))
return;
printf("\n\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiMakeHiddenVar("table", getTableVar());
preserveConstraints(fullTableName, db, NULL);
cgiContinueHiddenVar("position");
//#*** Really need to save this off to a local file!
cgiContinueHiddenVar("tbUserKeys");
printf(" Fields of %s: \n", getTableName());
descTable(TRUE);
puts(" ");
}
void doGetStatsNonpositional()
/* Print out statistics about nonpositional query results. */
{
struct sqlConnection *conn;
struct dyString *query = newDyString(256);
char *constraints;
char *table = getTableName();
char *db = getTableDb();
int numRows;
saveOutputOptionsState();
webStart(cart, "Table Browser: %s %s: %s", hOrganism(database),freezeName, statsPhase);
checkTableExists(fullTableName);
printf("\n\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiMakeHiddenVar("table", getTableVar());
displayPosition();
preserveConstraints(fullTableName, db, NULL);
cgiContinueHiddenVar("position");
printf("\n");
cgiMakeDropList("outputType", outputTypeNonPosMenu, outputTypeNonPosMenuSize,
statsPhase);
cgiMakeButton("phase", getOutputPhase);
puts(" ");
puts(" ");
puts(" "
"Help
");
printf("
Your query on %s: \n", table);
constraints = constrainFields(NULL);
if ((constraints != NULL) && (constraints[0] == 0))
constraints = NULL;
if (constraints != NULL)
printf("Constraints on %s: %s\n", table, constraints);
else
printf("No constraints selected on fields of %s.
\n", table);
dyStringClear(query);
dyStringPrintf(query, "select count(*) from %s%s%s", table,
(constraints ? " where " : ""),
(constraints ? constraints : ""));
conn = hAllocOrConnect(db);
numRows = sqlQuickNum(conn, query->string);
hFreeOrDisconnect(&conn);
printf("Number of rows in %s%s: %d
\n", table,
constraints ? " matching constraints" : "", numRows);
descForm();
webEnd();
}
struct slName *getOrderedChromList()
/* Put the _random's at the end, and break them into two lines. */
/* Also, put the alpha-name chroms after the numeric-name chroms. */
{
struct slName *randList = NULL, *nonrList = NULL;
struct slName *randAlphList = NULL, *nonrAlphList = NULL;
struct slName *chromPtr;
struct slName *chromList = hAllChromNames();
for (chromPtr=chromList; chromPtr != NULL; chromPtr=chromPtr->next)
{
struct slName *newEl = newSlName(chromPtr->name);
if (endsWith(chromPtr->name, "_random"))
{
if (isdigit(chromPtr->name[3]))
slAddHead(&randList, newEl);
else
slAddHead(&randAlphList, newEl);
}
else
{
if (isdigit(chromPtr->name[3]))
slAddHead(&nonrList, newEl);
else
slAddHead(&nonrAlphList, newEl);
}
}
slFreeList(&chromList);
slReverse(&nonrList);
slReverse(&nonrAlphList);
slReverse(&randList);
slReverse(&randAlphList);
slCat(randList, randAlphList);
slCat(nonrAlphList, randList);
chromList = slCat(nonrList, nonrAlphList);
return(chromList);
}
void getCumulativeStats(int **Xarrs, int *Ns, int num, struct intStats *stats)
/* Copy the arrays X[1]...X[num] into X[0], according to lengths in N.
* Put stats on X[0] into stats[0]. */
{
/* Actually, only go to the trouble if there are multiple arrays.
* If not, just copy the single array [1] to the cumulative location [0]. */
if (num > 1)
{
int i;
int offset = 0;
if (Ns[0] > 0)
{
Xarrs[0] = needMem(Ns[0] * sizeof(int));
for (i=1; i <= num; i++)
{
memcpy(Xarrs[0]+offset, Xarrs[i], Ns[i] * sizeof(int));
freez(&(Xarrs[i]));
offset += Ns[i];
}
assert(offset == Ns[0]);
intStatsFromArr(Xarrs[0], Ns[0], stats);
}
else
{
Xarrs[0] = NULL;
}
}
else
{
Xarrs[0] = Xarrs[1];
intStatsCopy(stats, &(stats[1]));
}
}
void getBedBaseCounts(struct bed *bedList, boolean hasBlocks,
int *utr5s, int *cdss, int *utr3s)
/* Given a list of beds with CDS, tally up the number of bases in
* 5'UTR, CDS and 3'UTR and store them in the count arrays. */
{
struct bed *bed;
int j;
for (bed=bedList, j=0; bed != NULL; bed=bed->next, j++)
{
int utr5=0, cds=0, utr3=0;
boolean isRc = (bed->strand[0] == '-');
if (hasBlocks)
{
int k;
for (k=0; k < bed->blockCount; k++)
{
int s = bed->chromStart + bed->chromStarts[k];
int e = s + bed->blockSizes[k];
if (e < bed->thickStart)
if (isRc)
utr3 += e - s;
else
utr5 += e - s;
else if (s < bed->thickStart)
if (e > bed->thickEnd)
{
cds += bed->thickEnd - bed->thickStart;
if (isRc)
{
utr3 += bed->thickStart - s;
utr5 += e - bed->thickEnd;
}
else
{
utr5 += bed->thickStart - s;
utr3 += e - bed->thickEnd;
}
}
else
{
cds += e - bed->thickStart;
if (isRc)
utr3 += bed->thickStart - s;
else
utr5 += bed->thickStart - s;
}
else if (s > bed->thickEnd)
if (isRc)
utr5 += e - s;
else
utr3 += e - s;
else if (e > bed->thickEnd)
{
cds += bed->thickEnd - s;
if (isRc)
utr5 += e - bed->thickEnd;
else
utr3 += e - bed->thickEnd;
}
else
cds += e - s;
}
}
else
{
cds = bed->thickEnd - bed->thickStart;
if (isRc)
{
utr3 = bed->thickStart - bed->chromStart;
utr5 = bed->chromEnd - bed->thickEnd;
}
else
{
utr5 = bed->thickStart - bed->chromStart;
utr3 = bed->chromEnd - bed->thickEnd;
}
}
utr5s[j] = utr5;
cdss[j] = cds;
utr3s[j] = utr3;
}
}
char *breakChromRandomName(char *name)
/* If name ends with _random, put an HTML linebreak in there. */
{
if (endsWith(name, "_random"))
{
char buf[32];
char *ptr = strstr(name, "_random");
*ptr = 0;
snprintf(buf, sizeof(buf), "%s_ random", name);
return(cloneString(buf));
}
else
return(cloneString(name));
}
void doGetStatsPositional()
/* Print out statistics about positional query results. */
{
struct hTableInfo *hti = getOutputHti();
struct slName *chromList, *chromPtr;
struct intStats *chromLengthStats;
struct intStats *scoreStats;
struct intStats *utr5Stats;
struct intStats *cdsStats;
struct intStats *utr3Stats;
struct intStats *blockCountStats;
struct intStats *blockSizeStats;
char *db = getTableDb();
char *table = getTableName();
char *db2 = getTable2Db();
char *table2 = getTable2Name();
char *op = cgiOptionalString("tbIntersectOp");
char *constraints, *constraints2;
int numChroms;
int numCols = 0;
int *itemCounts, *bitCounts, *itemUncCounts;
int *strandPCounts, *strandMCounts, *strandQCounts;
int **chromLengthArrs;
int **scoreArrs;
int **utr5Arrs;
int **cdsArrs;
int **utr3Arrs;
int **blockCountArrs;
int **blockSizeArrs;
int i, j;
boolean typeWiggle2 = FALSE;
boolean wiggleDone = FALSE;
saveOutputOptionsState();
saveIntersectOptionsState();
if (op == NULL)
table2 = NULL;
else
typeWiggle2 = isWiggle(db2, table2);
if (allGenome)
chromList = getOrderedChromList();
else
chromList = newSlName(chrom);
numChroms = slCount(chromList);
itemCounts = needMem((numChroms+1) * sizeof(int));
bitCounts = needMem((numChroms+1) * sizeof(int));
itemUncCounts = needMem((numChroms+1) * sizeof(int));
strandPCounts = needMem((numChroms+1) * sizeof(int));
strandMCounts = needMem((numChroms+1) * sizeof(int));
strandQCounts = needMem((numChroms+1) * sizeof(int));
chromLengthArrs = needMem((numChroms+1) * sizeof(int *));
chromLengthStats = needMem((numChroms+1) * sizeof(struct intStats));
scoreArrs = needMem((numChroms+1) * sizeof(int *));
scoreStats = needMem((numChroms+1) * sizeof(struct intStats));
utr5Arrs = needMem((numChroms+1) * sizeof(int *));
utr5Stats = needMem((numChroms+1) * sizeof(struct intStats));
cdsArrs = needMem((numChroms+1) * sizeof(int *));
cdsStats = needMem((numChroms+1) * sizeof(struct intStats));
utr3Arrs = needMem((numChroms+1) * sizeof(int *));
utr3Stats = needMem((numChroms+1) * sizeof(struct intStats));
blockCountArrs = needMem((numChroms+1) * sizeof(int *));
blockCountStats = needMem((numChroms+1) * sizeof(struct intStats));
blockSizeArrs = needMem((numChroms+1) * sizeof(int *));
blockSizeStats = needMem((numChroms+1) * sizeof(struct intStats));
webStart(cart, "Table Browser: %s %s: %s", hOrganism(database),freezeName, statsPhase);
checkTableExists(fullTableName);
printf("
\n\n",
hgTextName(), httpFormMethod);
cartSaveSession(cart);
cgiMakeHiddenVar("db", database);
cgiMakeHiddenVar("table", getTableVar());
displayPosition();
preserveConstraints(fullTableName, db, NULL);
preserveTable2();
printf("\n");
if (typeWiggle)
cgiMakeDropList("outputType", outputTypeWiggleMenu,
outputTypeWiggleMenuSize, statsPhase);
else
cgiMakeDropList("outputType", outputTypePosMenu,
outputTypePosMenuSize, statsPhase);
cgiMakeButton("phase", getOutputPhase);
puts(" ");
puts(" ");
puts(""
"Help ");
printf("
Your query on %s%s%s: \n", table,
(table2 != NULL) ? " vs. " : "",
(table2 != NULL) ? table2 : "");
constraints = constrainFields(NULL);
if ((constraints != NULL) && (constraints[0] == 0))
constraints = NULL;
constraints2 = constrainFields("2");
if ((constraints2 != NULL) && (constraints2[0] == 0))
constraints2 = NULL;
if (isBatch())
{
printf("Position range: previously uploaded set of names/accessions (");
printFirstNWords(getUserKeys(), 3, " ");
puts(" )");
}
else
printf("Position range: %s\n", position);
printf(" Primary table: %s\n", table);
if (constraints != NULL)
printf("
Constraints on %s: %s \n", table, constraints);
else
printf("
No additional constraints selected on fields of %s.\n", table);
if (typeWiggle)
{
if (wigConstraint[0])
{
if (sameWord(wigConstraint[0],"in range"))
printf("
data value constraint: %s [%g , %g]\n",
wigConstraint[0], wigDataConstraint[0][0],
wigDataConstraint[0][1]);
else
printf("
data value constraint: %s %g\n",
wigConstraint[0], wigDataConstraint[0][0]);
}
}
if (table2 != NULL)
{
char tableUse[128], table2Use[128];
printf("
Secondary table: %s\n", table2);
if (constraints2 != NULL)
printf("
Constraints on %s: %s\n", table2, constraints2);
else
printf("
No additional constraints selected on fields of %s.\n",
table2);
if (cgiBoolean("tbInvertTable"))
snprintf(tableUse, sizeof(tableUse), "complement of %s", table);
else
strncpy(tableUse, table, sizeof(tableUse));
if (cgiBoolean("tbInvertTable2"))
snprintf(table2Use, sizeof(table2Use), "complement of %s", table2);
else
strncpy(table2Use, table2, sizeof(table2Use));
puts("
Means of combining tables:");
if (sameString(op, "any"))
printf("Include %s records that have any overlap with %s
\n",
table, table2);
else if (sameString(op, "none"))
printf("Include %s records that have no overlap with %s
\n",
table, table2);
else if (sameString(op, "more"))
printf("Include %s records that have at least %s%% overlap with %s
\n",
table, cgiString("tbMoreThresh"), table2);
else if (sameString(op, "less"))
printf("Include %s records that have at most %s%% overlap with %s
\n",
table, cgiString("tbLessThresh"), table2);
else if (sameString(op, "and"))
printf("List positions of base pairs covered by both %s and %s
\n",
tableUse, table2Use);
else if (sameString(op, "or"))
printf("List positions of base pairs covered by either %s or %s
\n",
tableUse, table2Use);
else
errAbort("Unrecognized table combination type.");
if (typeWiggle2)
{
if (wigConstraint[1])
{
if (sameWord(wigConstraint[1],"in range"))
printf("
data value constraint: %s [%g , %g]\n",
wigConstraint[1], wigDataConstraint[1][0],
wigDataConstraint[1][1]);
else
printf("
data value constraint: %s %g\n",
wigConstraint[1], wigDataConstraint[1][0]);
}
}
}
/* Print out a big table of stats... only when not just one wiggle */
if (!(typeWiggle && (table2 == NULL)))
{
puts("
");
numCols = (numChroms > 1) ? numChroms+1 : 1;
for (chromPtr=chromList,i=1; chromPtr != NULL; chromPtr=chromPtr->next,i++)
{
struct bed *bedListConstr, *bed;
int count;
getFullTableName(fullTableName, chromPtr->name, table);
bedListConstr = getBedList(FALSE, chrom);
count = slCount(bedListConstr);
itemCounts[0] += count;
itemCounts[i] = count;
if (count > 0)
{
struct featureBits *fbList =
fbFromBed("out", hti, bedListConstr, winStart, winEnd,
FALSE, FALSE);
int chromSize = hChromSize(chrom);
Bits *bits = bitAlloc(chromSize+8);
fbOrBits(bits, chromSize, fbList, 0);
count = bitCountRange(bits, 0, chromSize);
bitFree(&bits);
}
else
count = 0;
bitCounts[0] += count;
bitCounts[i] = count;
if ((constraints != NULL)||((table2 != NULL)&&(constraints2 != NULL)))
{
struct bed *bedListUnc = getBedList(TRUE, chrom);
count = slCount(bedListUnc);
itemUncCounts[0] += count;
itemUncCounts[i] = count;
}
if (itemCounts[i] > 0)
{
chromLengthArrs[i] = needMem(itemCounts[i] * sizeof(int));
for (bed=bedListConstr, j=0; bed != NULL; bed=bed->next, j++)
chromLengthArrs[i][j] = bed->chromEnd - bed->chromStart;
intStatsFromArr(chromLengthArrs[i], itemCounts[i],
&(chromLengthStats[i]));
if (hti->scoreField[0] != 0)
{
scoreArrs[i] = needMem(itemCounts[i] * sizeof(int));
for (bed=bedListConstr, j=0; bed != NULL; bed=bed->next, j++)
scoreArrs[i][j] = bed->score;
intStatsFromArr(scoreArrs[i], itemCounts[i], &(scoreStats[i]));
}
if (hti->strandField[0] != 0)
{
for (bed=bedListConstr; bed != NULL; bed=bed->next)
{
if (bed->strand[0] == '+')
{
strandPCounts[0]++;
strandPCounts[i]++;
}
else if (bed->strand[0] == '-')
{
strandMCounts[0]++;
strandMCounts[i]++;
}
else
{
strandQCounts[0]++;
strandQCounts[i]++;
}
}
}
if (hti->hasCDS)
{
utr5Arrs[i] = needMem(itemCounts[i] * sizeof(int));
cdsArrs[i] = needMem(itemCounts[i] * sizeof(int));
utr3Arrs[i] = needMem(itemCounts[i] * sizeof(int));
getBedBaseCounts(bedListConstr, hti->hasBlocks,
utr5Arrs[i], cdsArrs[i], utr3Arrs[i]);
intStatsFromArr(utr5Arrs[i], itemCounts[i], &(utr5Stats[i]));
intStatsFromArr(cdsArrs[i], itemCounts[i], &(cdsStats[i]));
intStatsFromArr(utr3Arrs[i], itemCounts[i], &(utr3Stats[i]));
}
if (hti->hasBlocks)
{
blockCountArrs[i] = needMem(itemCounts[i] * sizeof(int));
blockSizeArrs[i] = needMem(itemCounts[i] * sizeof(int));
for (bed=bedListConstr, j=0; bed != NULL; bed=bed->next, j++)
{
int k, totalSize = 0;
if (bed->blockCount < 1)
errAbort("Illegal bed: appears to have blocks, but blockCount is %d (%s\t%d\t%d\t%s...)",
bed->blockCount, bed->chrom, bed->chromStart,
bed->chromEnd, bed->name);
blockCountArrs[i][j] = bed->blockCount;
for (k=0; k < bed->blockCount; k++)
totalSize += bed->blockSizes[k];
// we lose some granularity here, but not too much...
blockSizeArrs[i][j] = round(totalSize / bed->blockCount);
}
intStatsFromArr(blockCountArrs[i], itemCounts[i],
&(blockCountStats[i]));
intStatsFromArr(blockSizeArrs[i], itemCounts[i],
&(blockSizeStats[i]));
}
}
}
getCumulativeStats(chromLengthArrs, itemCounts, numChroms,
chromLengthStats);
if (hti->scoreField[0] != 0)
getCumulativeStats(scoreArrs, itemCounts, numChroms, scoreStats);
if (hti->hasCDS)
{
getCumulativeStats(utr5Arrs, itemCounts, numChroms, utr5Stats);
getCumulativeStats(cdsArrs, itemCounts, numChroms, cdsStats);
getCumulativeStats(utr3Arrs, itemCounts, numChroms, utr3Stats);
}
if (hti->hasBlocks)
{
getCumulativeStats(blockCountArrs,itemCounts,numChroms,blockCountStats);
getCumulativeStats(blockSizeArrs,itemCounts,numChroms,blockSizeStats);
}
}
if (typeWiggle)
{
wigDoStats(database, table, chromList, WIG_TABLE_1, constraints);
wiggleDone = TRUE;
}
if (typeWiggle2)
{
wigDoStats(db2, table2, chromList, WIG_TABLE_2, constraints2);
}
if (! wiggleDone)
{
// For some reason BORDER=1 does not work in our web.c nested table scheme.
// So use web.c's trick of using an enclosing table to provide a border.
puts("" "\n"
- "
");
- puts("");
+ "");
+ puts("");
/* Use fixed-font for decimal point/integer alignment. */
/* All these non-blocking spaces are to widen the first column so that some
* row descriptions below do not get wrapped (which would mess up the
* formatting of row contents). */
puts("statistic ");
/* These non-blocking spaces are for decimal point/integer alignment: */
puts("total ");
if (numCols > 1)
for (chromPtr=chromList; chromPtr != NULL; chromPtr=chromPtr->next)
printf("%s ", breakChromRandomName(chromPtr->name));
puts(" ");
puts("items matching query ");
for (i=0; i < numCols; i++)
printf("%d ",
itemCounts[i]);
puts(" ");
puts("bases covered by matching items ");
for (i=0; i < numCols; i++)
printf("%d ",
bitCounts[i]);
puts(" ");
if ((constraints != NULL) || ((table2 != NULL) && (constraints2 != NULL)))
{
puts("items without constraints ");
for (i=0; i < numCols; i++)
printf("%d ",
itemUncCounts[i]);
puts(" ");
}
if (itemCounts[0] > 0)
{
if (hti->strandField[0] != 0)
{
puts("items on strand: + - ? ");
for (i=0; i < numCols; i++)
printf(" %d %d %d ",
strandPCounts[i], strandMCounts[i], strandQCounts[i]);
puts(" ");
}
puts("(chromEnd - chromStart): min avg max stdev ");
for (i=0; i < numCols; i++)
printf(" %d %.2f %d %.2f ",
chromLengthStats[i].min, chromLengthStats[i].avg,
chromLengthStats[i].max, chromLengthStats[i].stdev);
puts(" ");
if (hti->scoreField[0] != 0)
{
puts("score: min avg max stdev ");
for (i=0; i < numCols; i++)
printf(" %d %.2f %d %.2f ",
scoreStats[i].min, scoreStats[i].avg,
scoreStats[i].max, scoreStats[i].stdev);
puts(" ");
}
if (hti->hasCDS != 0)
{
char *exons = hti->hasBlocks ? " exons" : "";
printf("bases in 5\' UTR%s: min avg max stdev \n",
exons);
for (i=0; i < numCols; i++)
printf(" %d %.2f %d %.2f ",
utr5Stats[i].min, utr5Stats[i].avg,
utr5Stats[i].max, utr5Stats[i].stdev);
puts(" ");
printf("bases in CDS%s: min avg max stdev \n",
exons);
for (i=0; i < numCols; i++)
printf(" %d %.2f %d %.2f ",
cdsStats[i].min, cdsStats[i].avg,
cdsStats[i].max, cdsStats[i].stdev);
puts(" ");
printf("bases in 3\' UTR%s: min avg max stdev \n",
exons);
for (i=0; i < numCols; i++)
printf(" %d %.2f %d %.2f ",
utr3Stats[i].min, utr3Stats[i].avg,
utr3Stats[i].max, utr3Stats[i].stdev);
puts(" ");
}
if (hti->hasBlocks != 0)
{
char *thingy = startsWith("psl", hti->type) ? "gapless block" : "exon";
printf("%ss: min avg max stdev \n",
thingy);
for (i=0; i < numCols; i++)
printf(" %d %.2f %d %.2f ",
blockCountStats[i].min, blockCountStats[i].avg,
blockCountStats[i].max, blockCountStats[i].stdev);
puts(" ");
printf("bases per %s: min avg max stdev \n",
thingy);
for (i=0; i < numCols; i++)
printf(" %d %.2f %d %.2f ",
blockSizeStats[i].min, blockSizeStats[i].avg,
blockSizeStats[i].max, blockSizeStats[i].stdev);
puts(" ");
}
}
puts("
");
puts("
");
} /* if (! wiggleDone) */
freez(&(chromLengthArrs[0]));
freez(&chromLengthArrs);
freez(&chromLengthStats);
if (hti->scoreField[0] != 0)
freez(&(scoreArrs[0]));
freez(&scoreArrs);
freez(&scoreStats);
if (hti->hasCDS)
{
freez(&(utr5Arrs[0]));
freez(&(cdsArrs[0]));
freez(&(utr3Arrs[0]));
}
if (hti->hasBlocks)
{
freez(&(blockCountArrs[0]));
freez(&(blockSizeArrs[0]));
}
freez(&utr5Arrs);
freez(&utr5Stats);
freez(&cdsArrs);
freez(&cdsStats);
freez(&utr3Arrs);
freez(&utr3Stats);
freez(&blockCountArrs);
freez(&blockCountStats);
freez(&blockSizeArrs);
freez(&blockSizeStats);
freez(&itemCounts);
freez(&bitCounts);
freez(&itemUncCounts);
freez(&strandPCounts);
freez(&strandMCounts);
freez(&strandQCounts);
descForm();
webEnd();
}
void doGetStats()
/* Print out statistics about the query results. */
{
if (tableIsPositional)
doGetStatsPositional();
else
doGetStatsNonpositional();
}
static int descendingFreqCmp(const void *el1, const void *el2)
/* descending sort on pointers to pointers to hash elements whose
* values are int (not pointer to int! because of hashAddInt()). */
{
const struct hashEl *hel1 = *((struct hashEl **)el1);
const struct hashEl *hel2 = *((struct hashEl **)el2);
int v1 = ptToInt(hel1->val);
int v2 = ptToInt(hel2->val);
int dif;
dif = v2 - v1;
if (dif == 0)
dif = strcmp(hel1->name, hel2->name);
return(dif);
}
void doGetHistogram()
/* Print out a histogram for the text value of some field. */
{
struct sqlConnection *conn;
struct sqlResult *sr;
struct dyString *query = newDyString(256);
struct hash *freqHash = newHash(16);
struct hashEl *els, *el;
struct slName *chromList, *chromPtr;
struct hash *nameHash = newHash(18);
struct slName *wildNames = NULL, *wild=NULL;
char **row;
char *words[5];
char *constraints;
char *table = getTableName();
char *db = getTableDb();
char *keyStr = getUserKeys();
char *word;
struct hTableInfo *hti = getHti(db, table);
char *phase = cgiString("phase");
char *field;
int count;
int maxFreq, freq;
int i;
double scale;
webStart(cart, "Table Browser: %s %s: %s", hOrganism(database),freezeName, histPhase);
checkTableExists(fullTableName);
count = chopLine(phase, words);
if (count < 4)
errAbort("doGetHistogram: CGI var phase should be of the form \"%s for XXXX\" where XXXX is a valid field name", histPhase);
field = words[3];
if (sameString(customTrackPseudoDb, db))
{
printf("Histograms are only supported on fields of database tables, not custom tracks.\n");
webEnd();
return;
}
constraints = constrainFields(NULL);
if ((constraints != NULL) && (constraints[0] == 0))
constraints = NULL;
if (allGenome && tableIsPositional)
chromList = hAllChromNames();
else
chromList = newSlName(chrom);
if (isBatch() && hti->nameField[0] != 0)
{
if (cgiVarExists("tbShowUploadResults"))
{
while ((word = nextWord(&keyStr)) != NULL)
{
hashAdd(nameHash, word, NULL);
}
}
else
{
while ((word = nextWord(&keyStr)) != NULL)
{
wild = slNameNew(word);
slAddHead(&wildNames, wild);
}
}
}
conn = hAllocOrConnect(db);
for (chromPtr=chromList; chromPtr != NULL; chromPtr=chromPtr->next)
{
getFullTableName(fullTableName, chromPtr->name, table);
if (! sqlTableExists(conn, fullTableName))
continue;
dyStringClear(query);
if (isBatch() && hti->nameField[0] != 0)
{
dyStringPrintf(query, "SELECT %s,%s FROM %s", field, hti->nameField,
fullTableName);
}
else
dyStringPrintf(query, "SELECT %s FROM %s", field, fullTableName);
if (tableIsPositional)
{
dyStringPrintf(query, " WHERE %s < %d AND %s > %d",
hti->startField, winEnd, hti->endField, winStart);
if (! sameString("", hti->chromField))
dyStringPrintf(query, " AND %s = \'%s\'",
hti->chromField, chrom);
if ((constraints != NULL) && (constraints[0] != 0))
dyStringPrintf(query, " AND %s", constraints);
}
else if (constraints)
dyStringPrintf(query, " WHERE %s", constraints);
sr = sqlGetResult(conn, query->string);
// make a hash of field values to frequencies,
// filtering with user keys if specified:
while ((row = sqlNextRow(sr)) != NULL)
{
if ((! isBatch()) || (hti->nameField[0] == 0) ||
(cgiVarExists("tbShowUploadResults") &&
(hashLookup(nameHash, row[1]) != NULL)) ||
(anyWildMatch(row[1], wildNames)))
{
if ((el = hashLookup(freqHash, row[0])) == NULL)
hashAddInt(freqHash, row[0], 1);
else
{
if (! sameString(el->name, row[0]))
printf("Hash-collision warning: %s --> %s\n",
el->name, row[0]);
(el->val) = intToPt(ptToInt(el->val) + 1);
}
}
}
sqlFreeResult(&sr);
}
hFreeOrDisconnect(&conn);
hashFree(&nameHash);
slFreeList(&wildNames);
// sort the elements by count, descending:
els = hashElListHash(freqHash);
if (els == NULL)
{
printf("No results returned from query.\n");
webEnd();
return;
}
slSort(&els, descendingFreqCmp);
maxFreq = ptToInt(els->val);
if (maxFreq > 50)
scale = (50.0 / maxFreq);
else
scale = 1.0;
// print out name, bar, count for each element
puts(""
"Help
");
printf("
Histogram of values for %s.%s%s%s, sorted by descending frequency: \n",
table, field,
(constraints? " " : ""),
(constraints? constraints : ""));
puts("");
printf("%50s %-50s %8s\n", "value", "", "count");
puts("--------------------------------------------------------------------------------------------------------------");
for (el = els; el != NULL; el=el->next)
{
printf("%50s ", el->name);
freq = ptToInt(el->val);
freq = (int)(scale * freq);
for (i=0; i < freq; i++)
putchar('*');
for (i=freq; i < 50; i++)
putchar(' ');
printf(" %8d\n", ptToInt(el->val));
}
puts(" ");
webEnd();
}
void doMiddle(struct cart *theCart)
/* the main body of the program */
{
char *table = NULL;
char *db = NULL;
char trash[32];
char *table2 = getTable2Name();
char *db2 = getTable2Db();
hgBotDelay();
cart = theCart;
table = getTableName();
db = getTableDb();
getDbAndGenome(cart, &database, &organism, oldVars);
database = cloneString(database);
hSetDb(database);
hDefaultConnect();
if ((table2 != NULL) && sameString(table2, "Choose table"))
table2 = NULL;
typeWiggle = isWiggle(db, table);
typeWiggle2 = isWiggle(db2, table2);
freezeName = hFreezeFromDb(database);
if (freezeName == NULL)
freezeName = "Unknown";
fullTableName[0] = 0;
position = getPosition(&chrom, &winStart, &winEnd);
allGenome = isGenome(position);
if (existsAndEqual("submit", "Look up") ||
(cgiOptionalString("phase") == NULL))
{
// Stay in same phase if we're just looking up position.
char *origPhase = cgiOptionalString("origPhase");
if (origPhase != NULL)
{
cgiVarSet("phase", origPhase);
cgiVarSet("tbPosOrKeys", "pos");
}
}
if (cgiOptionalString("phase") == NULL)
{
doGateway();
return;
}
else if (existsAndEqual("phase", chooseTablePhase))
{
doChooseTable();
}
else
{
if ((existsAndEqual("tbTrack", "Choose table") &&
existsAndEqual("tbCustomTrack", "Choose table") &&
existsAndEqual("table0", "Choose table") &&
existsAndEqual("table1", "Choose table")) ||
db == NULL || table == NULL)
webAbort("Missing table selection", "Please choose a table.");
if ((! sameString(database, db)) && (! sameString(hGetDb2(), db)) &&
(! sameString(customTrackPseudoDb, db)))
hSetDb2(db);
if (allGenome)
getFullTableName(fullTableName, NULL, table);
else
getFullTableName(fullTableName, chrom, table);
if (sameString(customTrackPseudoDb, db))
tableIsPositional = TRUE;
else
tableIsPositional = hFindChromStartEndFieldsDb(db, fullTableName,
trash, trash, trash);
if (strstr(table, "chrN_") == table)
tableIsSplit = TRUE;
if (existsAndEqual("phase", outputOptionsPhase))
doOutputOptions();
else if (existsAndEqual("phase", getOutputPhase))
{
if (existsAndEqual("outputType", allFieldsPhase) ||
existsAndEqual("outputType", oldAllFieldsPhase))
doTabSeparated(TRUE);
else if (existsAndEqual("outputType", chooseFieldsPhase))
doChooseFields();
else if (existsAndEqual("outputType", seqOptionsPhase) ||
existsAndEqual("outputType", oldSeqOptionsPhase))
doSequenceOptions();
else if (existsAndEqual("outputType", gffPhase))
doGetGFF();
else if (existsAndEqual("outputType", bedOptionsPhase))
doBedCtOptions(FALSE);
else if (existsAndEqual("outputType", ctOptionsPhase))
doBedCtOptions(TRUE);
else if (existsAndEqual("outputType", linksPhase))
doGetBrowserLinks();
else if (existsAndEqual("outputType", statsPhase))
doGetStats();
else if (existsAndEqual("outputType", ctWigOptionsPhase))
doWiggleCtOptions(TRUE);
else if (existsAndEqual("outputType", wigOptionsPhase))
doWiggleCtOptions(FALSE);
else
webAbort("Table Browser: CGI option error",
"Error: unrecognized value of CGI var outputType: %s",
cgiUsualString("outputType", "(Undefined)"));
}
else if (existsAndEqual("phase", pasteNamesPhase))
pasteForm();
else if (existsAndEqual("phase", uploadNamesPhase))
uploadForm();
else if (existsAndEqual("phase", allFieldsPhase) ||
existsAndEqual("phase", oldAllFieldsPhase))
doTabSeparated(TRUE);
else if (existsAndEqual("phase", chooseFieldsPhase))
doChooseFields();
else if (existsAndEqual("phase", getSomeFieldsPhase))
doTabSeparated(FALSE);
else if (existsAndEqual("phase", seqOptionsPhase) ||
existsAndEqual("phase", oldSeqOptionsPhase))
doSequenceOptions();
else if (existsAndEqual("phase", getSequencePhase))
doGetSequence();
else if (existsAndEqual("phase", gffPhase))
doGetGFF();
else if (existsAndEqual("phase", bedOptionsPhase))
doBedCtOptions(FALSE);
else if (existsAndEqual("phase", getCtWiggleTrackPhase))
doGetWiggleData(DO_CT_DATA);
else if (existsAndEqual("phase", getCtWiggleFilePhase))
doGetWiggleData(NOT_CT_DATA);
else if (existsAndEqual("phase", ctWigOptionsPhase))
doWiggleCtOptions(TRUE);
else if (existsAndEqual("phase", wigOptionsPhase))
doWiggleCtOptions(FALSE);
else if (existsAndEqual("phase", getWigglePhase))
doGetWiggleData(NOT_CT_DATA);
else if (existsAndEqual("phase", ctOptionsPhase))
doBedCtOptions(TRUE);
else if (existsAndEqual("phase", getBedPhase))
doGetBedCt(FALSE);
else if (existsAndEqual("phase", getCtBedPhase))
doGetBedCt(FALSE);
else if (existsAndEqual("phase", getCtPhase))
doGetBedCt(TRUE);
else if (existsAndEqual("phase", linksPhase))
doGetBrowserLinks();
else if (existsAndEqual("phase", statsPhase))
doGetStats();
else if (existsAndEqual("phase", intersectOptionsPhase))
doIntersectOptions();
else if (existsAndStartsWith("phase", histPhase))
doGetHistogram();
else if (existsAndStartsWith("phase", descTablePhase))
doDescTable();
else
webAbort("Table Browser: CGI option error",
"Error: unrecognized value of CGI var phase: %s",
cgiUsualString("phase", "(Undefined)"));
}
cartSetString(cart, "db", database);
cartSetString(cart, "org", organism);
if (position != NULL)
cartSetString(cart, "position", position);
}
/* Null terminated list of CGI Variables we don't want to save
* permanently. */
char *excludeVars[] = {"Submit", "submit",
"tbUserKeys",
"tbShowPasteResults", "tbShowUploadResults", NULL};
int main(int argc, char *argv[])
/* Process command line. */
{
struct cart *theCart;
oldVars = hashNew(10);
cgiSpoof(&argc, argv);
/* Sometimes we output HTML and sometimes plain text; let each outputter
* take care of headers instead of using a fixed cart*Shell(). */
theCart = cartAndCookieWithHtml(hUserCookie(), excludeVars, oldVars, FALSE);
doMiddle(theCart);
cartCheckout(&theCart);
return 0;
}