Skip to content

Disable LabKey caching of ResultSet by default#7711

Open
labkey-jeckels wants to merge 9 commits into
developfrom
fb_disableCacheByDefault
Open

Disable LabKey caching of ResultSet by default#7711
labkey-jeckels wants to merge 9 commits into
developfrom
fb_disableCacheByDefault

Conversation

@labkey-jeckels
Copy link
Copy Markdown
Contributor

@labkey-jeckels labkey-jeckels commented Jun 2, 2026

Rationale

We don't want to cache more than we need to. We just disabled Postgres JDBC caching for QueryService.getSelectBuilder() scenarios. Most scenarios shouldn't need a LabKey cache either.

Changes

  • Stop using CachedResultSet by default
  • Opt in to caching when needed
  • Tests for result set scrollability
  • Improve generics
  • Migrate remaining QueryService.select() and QueryService.selector() methods to QueryService.getSelectBuilder()

Tasks 📍

  • Claude Code Review
  • Manual Testing
  • Test Automation

@labkey-jeckels labkey-jeckels self-assigned this Jun 2, 2026
@labkey-jeckels
Copy link
Copy Markdown
Contributor Author

labkey-jeckels and others added 2 commits June 3, 2026 20:50
QueryHelper funnels every select through SelectBuilder.select(), whose default flipped to an uncached, streaming result set on this branch. Many QueryHelper callers (15 files across wnprc-modules, ehrModules, OConnorLabModules, and premiumModules) rely on the cached result set's full API — particularly getRowMap(), which a streaming result set does not support. In wnprc-modules' SimpleQuery the resulting UnsupportedOperationException is swallowed and surfaces as an empty result, causing WNPRC_EHRTest's consistent "Account acct103 not found in aliases table" setup failure on this branch. Request a cached result set explicitly to preserve the helper's longstanding semantics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@labkey-adam labkey-adam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments to consider, but no further review required

tableMap.put("__DATA", assayDataTable);

try (ResultSet rs = QueryService.get().select(schema, sqlf.getSQL(), tableMap, false, true))
try (ResultSet rs = QueryService.get().getSelectBuilder(schema, sqlf.getSQL(), false, tableMap).select(true))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want getSelectBuilder() to take a SQLFragment?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@labkey-matthewb and I discussed this. Ultimately, we want it to take a LabKeySQLFragment or similar and keep SQLFragment for raw DB SQL.

ArrayList<String> ids = new ArrayList<>();
while (rs.next())
ids.add(rs.getString(1));
return ids;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we'd convert this all to .buildSqlSelector().getArrayList(String.class); Maybe that's for another day.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I don't want to figure out how to test this right now.

default Results select()
{
return select(true);
return select(false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe too late for this, but it would be nice to replace the various boolean parameters with enums that elucidate the behaviors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea for next time.

return select.select();
// select(true): legacy callers (especially EHR modules) rely on the cached result set's full API,
// e.g. getRowMap(), which a streaming result set does not support
return select.select(true);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Boo

dcMySampleParent = mySampleParent.getRenderer();

assertTrue(results.next());
ctx.setRow(results.getRowMap());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling getRowMap() requires a cached Results, right? Should we document that method as such?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JavaDoc added.

}
if (!_container.equals(that._container)) return false;
return _schema.equals(that._schema);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the default equals() essentially this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems odd to remove hashCode() but not equals()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Removed. I told IntelliJ to automatically apply some auto-refactors on save and it's surprisingly aggressive at converting some classes to records.

return false;

return true;
if (obj instanceof SessionQuery(String sql, String metadata))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoa, what is this strange syntax? Is that strictly a record thing?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, default equals() won't do here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing. Simplified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants