206b0af134d75c2397b56a7ee65800a1eb5456a0 galt Mon Jan 29 21:15:07 2018 -0800 Use sqlSafef family of functions for safety and consistency. diff --git src/hg/lib/tablesTables.c src/hg/lib/tablesTables.c index 830ef6f..e4db6c8 100644 --- src/hg/lib/tablesTables.c +++ src/hg/lib/tablesTables.c @@ -407,142 +407,147 @@ FALSE, NULL, slCount(table->rowList), NULL, NULL, NULL); } void webTableBuildQuery(struct cart *cart, char *from, char *initialWhere, char *varPrefix, char *fields, boolean withFilters, struct dyString **retQuery, struct dyString **retWhere) /* Construct select, from and where clauses in query, keeping an additional copy of where * Returns the SQL query and the SQL where expression as two dyStrings (need to be freed) */ { struct dyString *query = dyStringNew(0); struct dyString *where = dyStringNew(0); struct slName *field, *fieldList = commaSepToSlNames(fields); boolean gotWhere = FALSE; -sqlDyStringPrintf(query, "%s", ""); // TODO check with Galt on how to get reasonable checking back. -dyStringPrintf(query, "select %s from %s", fields, from); +sqlDyStringPrintf(query, "select %s from %s", fields, from); if (!isEmpty(initialWhere)) { - dyStringPrintf(where, " where "); + sqlDyStringPrintfFrag(where, " where "); sqlSanityCheckWhere(initialWhere, where); gotWhere = TRUE; } /* If we're doing filters, have to loop through the row of filter controls */ if (withFilters) { for (field = fieldList; field != NULL; field = field->next) { char varName[128]; safef(varName, sizeof(varName), "%s_f_%s", varPrefix, field->name); char *val = trimSpaces(cartUsualString(cart, varName, "")); if (!isEmpty(val)) { if (gotWhere) - dyStringPrintf(where, " and "); + sqlDyStringPrintf(where, " and "); else { - dyStringPrintf(where, " where "); + sqlDyStringPrintf(where, " where "); gotWhere = TRUE; } if (anyWild(val)) { char *converted = sqlLikeFromWild(val); - char *escaped = makeEscapedString(converted, '"'); - dyStringPrintf(where, "%s like \"%s\"", field->name, escaped); - freez(&escaped); + sqlDyStringPrintf(where, "%s like '%s'", field->name, converted); freez(&converted); } else if (val[0] == '>' || val[0] == '<') { char *remaining = val+1; if (remaining[0] == '=') + { remaining += 1; + } remaining = skipLeadingSpaces(remaining); if (isNumericString(remaining)) - dyStringPrintf(where, "%s %s", field->name, val); + { + sqlDyStringPrintf(where, "%s ", field->name); + if (val[0] == '>') + sqlDyStringPrintf(where, ">"); + if (val[0] == '<') + sqlDyStringPrintf(where, "<"); + if (val[1] == '=') + sqlDyStringPrintf(where, "="); + sqlDyStringPrintf(where, "%s", remaining); + } else { warn("Filter for %s doesn't parse: %s", field->name, val); - dyStringPrintf(where, "%s is not null", field->name); // Let query continue + sqlDyStringPrintf(where, "%s is not null", field->name); // Let query continue } } else { - char *escaped = makeEscapedString(val, '"'); - dyStringPrintf(where, "%s = \"%s\"", field->name, escaped); - freez(&escaped); + sqlDyStringPrintf(where, "%s = '%s'", field->name, val); } } } } -dyStringAppend(query, where->string); +sqlDyStringPrintf(query, "%-s", where->string); // trust /* We do order here so as to keep order when working with tables bigger than a page. */ char orderVar[256]; safef(orderVar, sizeof(orderVar), "%s_order", varPrefix); char *orderFields = cartUsualString(cart, orderVar, ""); if (!isEmpty(orderFields)) { if (orderFields[0] == '-') - dyStringPrintf(query, " order by %s desc", orderFields+1); + sqlDyStringPrintf(query, " order by %s desc", orderFields+1); else - dyStringPrintf(query, " order by %s", orderFields); + sqlDyStringPrintf(query, " order by %s", orderFields); } // return query and where expression *retQuery = query; *retWhere = where; } void webFilteredSqlTable(struct cart *cart, struct sqlConnection *conn, char *fields, char *from, char *initialWhere, char *returnUrl, char *varPrefix, int maxFieldWidth, struct hash *tagOutWrappers, void *wrapperContext, boolean withFilters, char *itemPlural, int pageSize, struct hash *suggestHash, void (*addFunc)(void) ) /* Given a query to the database in conn that is basically a select query broken into * separate clauses, construct and display an HTML table around results. This HTML table has * column names that will sort the table, and optionally (if withFilters is set) * it will also allow field-by-field wildcard queries on a set of controls it draws above * the labels. * Much of the functionality rests on the call to webFilteredFieldedTable. This function * does the work needed to bring in sections of potentially huge results sets into * the fieldedTable. */ { struct dyString *query; struct dyString *where; webTableBuildQuery(cart, from, initialWhere, varPrefix, fields, withFilters, &query, &where); /* Figure out size of query result */ struct dyString *countQuery = dyStringNew(0); -sqlDyStringPrintf(countQuery, "%s", ""); // TODO check with Galt on how to get reasonable checking back. -dyStringPrintf(countQuery, "select count(*) from %s", from); -dyStringAppend(countQuery, where->string); +sqlDyStringPrintf(countQuery, "select count(*) from %s", from); +sqlDyStringPrintf(countQuery, "%-s", where->string); // trust int resultsSize = sqlQuickNum(conn, countQuery->string); dyStringFree(&countQuery); char pageVar[64]; safef(pageVar, sizeof(pageVar), "%s_page", varPrefix); int page = 0; struct fieldedTableSegment context = { .tableSize=resultsSize}; if (resultsSize > pageSize) { page = cartUsualInt(cart, pageVar, 0) - 1; if (page < 0) page = 0; int lastPage = (resultsSize-1)/pageSize; if (page > lastPage) page = lastPage; context.tableOffset = page * pageSize; - dyStringPrintf(query, " limit %d offset %d", pageSize, context.tableOffset); + sqlDyStringPrintf(query, " limit %d offset %d", pageSize, context.tableOffset); } struct fieldedTable *table = fieldedTableFromDbQuery(conn, query->string); webFilteredFieldedTable(cart, table, returnUrl, varPrefix, maxFieldWidth, tagOutWrappers, wrapperContext, withFilters, itemPlural, pageSize, &context, suggestHash, addFunc); fieldedTableFree(&table); dyStringFree(&query); dyStringFree(&where); }