Skip to content

fix: chunk merged IDs in runBasicLinksQueryForIds to avoid SQLite parameter limit #2965

Description

@coderabbitai

Summary

runBasicLinksQueryForIds in lib/database/database.dart builds a single to_id IN (…) query over the full merged wave set. When many concurrent callers coalesce in one microtask (e.g. the DailyOS prefetch window), the merged set can exceed SQLite's default SQLITE_MAX_VARIABLE_NUMBER (999), causing a runtime error.

Root cause

The method currently passes ids.toList() directly to the Drift query without chunking:

Future<List<EntryLink>> runBasicLinksQueryForIds(Set<String> ids) async {
  final rows =
      await (select(linkedEntries)..where(
            (t) => t.toId.isIn(ids.toList()) & t.type.equals('BasicLink'),
          ))
          .get();
  return rows.map(entryLinkFromLinkedDbEntry).toList();
}

Proposed fix

Mirror the chunking pattern from runRatingsForTimeEntriesQueryForIds (added in PR #2964), using the existing _sqliteInListChunk = 500 constant:

Future<List<EntryLink>> runBasicLinksQueryForIds(Set<String> ids) async {
  final idList = ids.toList(growable: false);
  if (idList.length <= _sqliteInListChunk) {
    final rows = await (select(linkedEntries)..where(
          (t) => t.toId.isIn(idList) & t.type.equals('BasicLink'),
        )).get();
    return rows.map(entryLinkFromLinkedDbEntry).toList();
  }
  final combined = <EntryLink>[];
  for (var i = 0; i < idList.length; i += _sqliteInListChunk) {
    final end = (i + _sqliteInListChunk).clamp(0, idList.length);
    final chunk = idList.sublist(i, end);
    final rows = await (select(linkedEntries)..where(
          (t) => t.toId.isIn(chunk) & t.type.equals('BasicLink'),
        )).get();
    combined.addAll(rows.map(entryLinkFromLinkedDbEntry));
  }
  return combined;
}

Since _PendingLinksWave.mergedIds is a Set, each toId appears in exactly one chunk, so the semantics of the coalesced wave are fully preserved.

References

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions