e47b56dbd11cb3936098df9694704fc8ea086a67 angie Wed Dec 21 15:11:55 2016 -0800 hgTables was missing support for "comma" or "separator" field in non-primary field lines of all.joiner. refs #18586 diff --git src/hg/hgTables/joining.c src/hg/hgTables/joining.c index 75a25e2..0b2e94b 100644 --- src/hg/hgTables/joining.c +++ src/hg/hgTables/joining.c @@ -552,31 +552,31 @@ } void dyStringAddList(struct dyString *dy, char *s) /* Add s to end of string. If string is non-empty * first add comma. This make it relatively easy to * build up comma-separates lists. */ { if (dy->stringSize > 0) dyStringAppendC(dy, ','); dyStringAppend(dy, s); } void tjLoadSome(struct region *regionList, struct joinedTables *joined, int fieldOffset, int keyOffset, char *idField, struct hash *idHash, - struct slName *chopBefore, struct slName *chopAfter, + struct joinerField *jf, struct tableJoiner *tj, boolean isPositional, boolean isFirst) /* Load up rows. */ { struct region *region; struct dyString *sqlFields = dyStringNew(0); struct joinerDtf *dtf; struct slRef *ref; struct joinerPair *jp; int fieldCount = 0, keyCount = 0; int idFieldIx = -1; struct sqlConnection *conn = hAllocConn(tj->database); char *identifierFilter = NULL; boolean needUpdateFilter = FALSE; struct joinedRow *jr; @@ -646,43 +646,59 @@ break; } else { char *id = row[idFieldIx]; if (isFirst) { if (hashLookup(idHash, id)) { if (jrRowAdd(joined, row, fieldCount, keyCount) == NULL) break; } } else { + // chop id column by jf->separator if necessary + int sepCount = 0; + if (jf && isNotEmpty(jf->separator)) + sepCount = countChars(id, jf->separator[0]); + int wordCount = sepCount + 1; + char *idWords[wordCount]; + if (wordCount > 1) + chopString(id, jf->separator, idWords, ArraySize(idWords)); + else + idWords[0] = id; + int i; + for (i = 0; i < wordCount; i++) + { + struct slName *chopBefore = jf ? jf->chopBefore : NULL; + struct slName *chopAfter = jf ? jf->chopAfter : NULL; + idWords[i] = chopKey(chopBefore, chopAfter, trimSpaces(idWords[i])); struct hashEl *bucket; - id = chopKey(chopBefore, chopAfter, id); - for (bucket = hashLookup(idHash, id); bucket != NULL; + for (bucket = hashLookup(idHash, idWords[i]); bucket != NULL; bucket = hashLookupNext(bucket)) { jr = bucket->val; jr->hitThisTable = TRUE; jrRowExpand(joined, jr, row, fieldOffset, fieldCount, keyOffset, keyCount); } } } } + } sqlFreeResult(&sr); freez(&filter); if (!isPositional) break; } if (isFirst) slReverse(&joined->rowList); if (needUpdateFilter) { for (jr = joined->rowList; jr != NULL; jr = jr->next) { jr->passedFilter &= jr->hitThisTable; } } tj->loaded = TRUE; @@ -691,31 +707,31 @@ struct joinedTables *tjLoadFirst(struct region *regionList, struct tableJoiner *tj, int totalFieldCount, int totalKeyCount, int maxRowCount) /* Load up first table in series of joined tables. This allocates * field and key arrays big enough for all. */ { struct joinedTables *joined = joinedTablesNew(totalFieldCount, totalKeyCount, maxRowCount); struct hash *idHash = NULL; struct hTableInfo *hti = getHtiOnDb(tj->database, tj->table); char *idField = getIdField(tj->database, curTrack, tj->table, hti); if (idField != NULL) idHash = identifierHash(tj->database, tj->table); tjLoadSome(regionList, joined, 0, 0, - idField, idHash, NULL, NULL, tj, + idField, idHash, NULL, tj, isPositional(tj->database, tj->table), TRUE); hashFree(&idHash); return joined; } int findDtfIndex(struct joinerDtf *list, struct joinerDtf *dtf) /* Find dtf on list. */ { struct joinerDtf *el; int ix; for (el = list, ix=0; el != NULL; el = el->next, ++ix) { if (sameString(el->database, dtf->database) && sameString(el->table, dtf->table) && sameString(el->field, dtf->field)) @@ -870,31 +886,31 @@ internalErr(); } jfB = findJoinerField(route->identifier, route->b); if (jfB == NULL) internalErr(); if (!tj->loaded) { int keyIx; struct hash *keyHash = NULL; keyIx = findDtfIndex(joined->keyList, route->a); if (keyIx < 0) internalErr(); keyHash = hashKeyField(joined, keyIx, jfA); tjLoadSome(regionList, joined, curFieldCount, curKeyCount, route->b->field, keyHash, - jfB->chopBefore, jfB->chopAfter, + jfB, tj, isPositional(tj->database, tj->table), FALSE); curKeyCount += slCount(tj->keysOut); curFieldCount += slCount(tj->fieldList); hashFree(&keyHash); } } joinerDtfFreeList(&tableDtfs); hashFree(&tableHash); tableJoinerFreeList(&tjList); return joined; } static boolean allSameTable(struct joinerDtf *fieldList, struct joinerDtf *filterTables) /* Return TRUE if all db/tables in fieldList and filterTables are same. */ {