5f552f1a0ee9b190c5c88434da3327c323afc797 kent Wed Jun 8 14:26:20 2016 -0700 Moving bits of tdbQuery that checked for fields not existing in a query statement to rqlParse.c, and making cdwQuery do this check as well. diff --git src/lib/rqlParse.c src/lib/rqlParse.c index 55581af..79082b6 100644 --- src/lib/rqlParse.c +++ src/lib/rqlParse.c @@ -703,30 +703,132 @@ if (extra != NULL) errAbort("Extra stuff starting with '%s' past end of statement line %d of %s", extra, lf->lineIx, lf->fileName); return rql; } struct rqlStatement *rqlStatementParseString(char *string) /* Return a parsed-out RQL statement based on string */ { struct lineFile *lf = lineFileOnString("query", TRUE, cloneString(string)); struct rqlStatement *rql = rqlStatementParse(lf); lineFileClose(&lf); return rql; } +// Specialized wildHash could be added to hash.c, but will be so rarely used. +// It's purpose here is for wildCard tagTypes (e.g. "*Filter") which get +// loaded into an RA hash but require specialized hashFindVal to pick them up. +#define WILD_CARD_HASH_BIN "[wildCardHash]" +#define WILD_CARD_HASH_EMPTY "[]" +int wildExpressionCmp(const void *va, const void *vb) +/* Compare two slPairs. */ +{ +const struct slPair *a = *((struct slPair **)va); +const struct slPair *b = *((struct slPair **)vb); +return (strlen(a->name) - strlen(b->name)); +} + +struct slPair *wildHashMakeList(struct hash *hash) +/* Makes a sub hash containing a list of hash elements whose names contain wildcards ('*', '?'). + The sub hash will be put into WILD_CARD_HASH_BIN for use by wildHashLookup(). */ +{ +struct slPair *wildList = NULL; +struct hashEl* hel = NULL; +struct hashCookie cookie = hashFirst(hash); +while ((hel = hashNext(&cookie)) != NULL) + { + if (strchr(hel->name,'*') != NULL || strchr(hel->name,'?') != NULL) + slPairAdd(&wildList, hel->name, hel); + } +if (wildList == NULL) // Note: adding an "empty" pair will + slPairAdd(&wildList, WILD_CARD_HASH_EMPTY, NULL); // prevent rebuilding this list +else if (slCount(wildList) > 1) + slSort(&wildList,wildExpressionCmp); // sort on length, so the most restrictive + // wildcard match goes first? +hashAdd(hash, WILD_CARD_HASH_BIN, wildList); +return wildList; +} + +struct hashEl *wildHashLookup(struct hash *hash, char *name) +/* If wildcards are in hash, then look up var in "wildCardHash" bin. */ +{ +struct slPair *wild = hashFindVal(hash, WILD_CARD_HASH_BIN); +if (wild == NULL) // Hasn't been made yet. + wild = wildHashMakeList(hash); +if (wild == NULL +|| (slCount(wild) == 1 && sameString(wild->name,WILD_CARD_HASH_EMPTY))) + return NULL; // Empty list means hash contains no names with wildcards + +for ( ;wild != NULL; wild=wild->next) + if (wildMatch(wild->name,name)) + return wild->val; + +return NULL; +} + +static void *wildHashFindVal(struct hash *hash, char *name) +/* If wildcards are in hash, then look up var in "wildCardHash" bin. */ +{ +struct hashEl *hel = wildHashLookup(hash,name); +if (hel != NULL) + return hel->val; +return NULL; +} + +static struct hashEl *hashLookupEvenInWilds(struct hash *hash, char *name) +/* Lookup hash el but if no exact match look for wildcards in hash and then match. */ +{ +struct hashEl *hel = hashLookup(hash, name); +if (hel == NULL) + hel = wildHashLookup(hash, name); +return hel; +} + +void *rqlHashFindValEvenInWilds(struct hash *hash, char *name) +/* Find hash val but if no exact match look for wildcards in hash and then match. */ +{ +void *val = hashFindVal(hash, name); +if (val == NULL) + val = wildHashFindVal(hash, name); +return val; +} + + +void rqlCheckFieldsExist(struct rqlStatement *rql, + struct hash *fieldsThatExist, char *fieldSource) +/* Check that all fields referenced in an rql statement actually exist. + * fieldsThatExist is a hash of field names, and fieldSource is where they came from. */ +{ +/* Do checks that tags are all legitimate and with correct types. */ +struct slName *field; +for (field = rql->fieldList; field != NULL; field = field->next) + { + if (!anyWild(field->name)) + if (!hashLookupEvenInWilds(fieldsThatExist, field->name)) + errAbort("Field %s in query doesn't exist in %s.", field->name, fieldSource); + } +struct slName *var; +for (var = rql->whereVarList; var != NULL; var = var->next) + { + if (!hashLookupEvenInWilds(fieldsThatExist, var->name)) + errAbort("Tag %s doesn't exist. Maybe you mispelled a variable or forgot to put quotes " + "around\na word? Maybe %s is hosed?.", var->name, fieldSource); + } +} + + void rqlStatementDump(struct rqlStatement *rql, FILE *f) /* Print out statement to file. */ { fprintf(f, "%s:", rql->command); if (rql->fieldList) { fprintf(f, " "); struct slName *field = rql->fieldList; fprintf(f, "%s", field->name); for (field = field->next; field != NULL; field = field->next) fprintf(f, ",%s", field->name); } fprintf(f, "\n"); if (rql->tableList) {