Skip to content

Commit f08fddf

Browse files
Use UNION instead
1 parent 4110173 commit f08fddf

File tree

1 file changed

+44
-41
lines changed

1 file changed

+44
-41
lines changed

firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLiteIndexManager.java

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -190,59 +190,73 @@ public Set<DocumentKey> getDocumentsMatchingTarget(Target target) {
190190
}
191191

192192
Set<DocumentKey> result = new HashSet<>();
193-
BindArgs bindArgs;
193+
SQLitePersistence.Query query;
194194

195195
Object[] lowerBoundValues = encodeTargetValues(fieldIndex, target, lowerBound.getPosition());
196196
String lowerBoundOp = lowerBound.isBefore() ? ">=" : ">"; // `startAt()` versus `startAfter()`
197197
if (upperBound != null) {
198198
Object[] upperBoundValues = encodeTargetValues(fieldIndex, target, upperBound.getPosition());
199199
String upperBoundOp = upperBound.isBefore() ? "<" : "<="; // `endBefore()` versus `endAt()`
200-
bindArgs = generateBindArgs(lowerBoundValues, lowerBoundOp, upperBoundValues, upperBoundOp);
200+
query =
201+
generateQuery(
202+
fieldIndex.getIndexId(),
203+
lowerBoundValues,
204+
lowerBoundOp,
205+
upperBoundValues,
206+
upperBoundOp);
201207
} else {
202-
bindArgs = generateBindArgs(lowerBoundValues, lowerBoundOp);
208+
query = generateQuery(fieldIndex.getIndexId(), lowerBoundValues, lowerBoundOp);
203209
}
204210

205-
String sql =
206-
String.format(
207-
"SELECT document_name from index_entries WHERE index_id = %s AND (%s)",
208-
fieldIndex.getIndexId(), bindArgs.sql);
209-
db.query(sql)
210-
.binding(bindArgs.bindArgs)
211-
.forEach(
212-
row -> result.add(DocumentKey.fromPath(ResourcePath.fromString(row.getString(0)))));
211+
query.forEach(
212+
row -> result.add(DocumentKey.fromPath(ResourcePath.fromString(row.getString(0)))));
213213

214214
// TODO(indexing): Add limit handling
215215

216216
Logger.debug(TAG, "Index scan returned %s documents", result.size());
217217
return result;
218218
}
219219

220-
/** Returns a SQL filter that concatenates all {@code value} into a disjunction. */
221-
private BindArgs generateBindArgs(Object[] values, String op) {
222-
String[] filters = new String[values.length];
223-
for (int i = 0; i < values.length; ++i) {
224-
filters[i] = String.format("index_value %s ?", op);
220+
/** Returns a SQL query on 'index_entries' that unions all bounds. */
221+
private SQLitePersistence.Query generateQuery(int indexId, Object[] bounds, String op) {
222+
String[] statements = new String[bounds.length];
223+
Object[] bingArgs = new Object[bounds.length * 2];
224+
for (int i = 0; i < bounds.length; ++i) {
225+
statements[i] =
226+
String.format(
227+
"SELECT document_name FROM index_entries WHERE index_id = ? AND index_value %s ?",
228+
op);
229+
bingArgs[i * 2] = indexId;
230+
bingArgs[i * 2 + 1] = bounds[i];
225231
}
226-
return new BindArgs(TextUtils.join(" OR ", filters), values);
232+
String sql = TextUtils.join(" UNION ", statements);
233+
return db.query(sql).binding(bingArgs);
227234
}
228235

229-
/**
230-
* Returns a SQL filter that combines each element from the left list with each element from the
231-
* right list and returns all combinations (e.g. `(left1 AND right1) OR (left1 AND right2) ...`).
232-
*/
233-
private BindArgs generateBindArgs(Object[] left, String leftOp, Object[] right, String rightOp) {
234-
String[] filters = new String[left.length * right.length];
235-
Object[] bingArgs = new Object[left.length * right.length * 2];
236+
/** Returns a SQL query on 'index_entries' that unions all bounds. */
237+
private SQLitePersistence.Query generateQuery(
238+
int indexId,
239+
Object[] lowerBounds,
240+
String lowerBoundOp,
241+
Object[] upperBounds,
242+
String upperBoundOp) {
243+
String[] statements = new String[lowerBounds.length * upperBounds.length];
244+
Object[] bingArgs = new Object[lowerBounds.length * upperBounds.length * 3];
236245
int i = 0;
237-
for (Object value1 : left) {
238-
for (Object value2 : right) {
239-
filters[i] = String.format("index_value %s ? AND index_value %s ?", leftOp, rightOp);
240-
bingArgs[i * 2] = value1;
241-
bingArgs[i * 2 + 1] = value2;
246+
for (Object value1 : lowerBounds) {
247+
for (Object value2 : upperBounds) {
248+
statements[i] =
249+
String.format(
250+
"SELECT document_name FROM index_entries WHERE index_id = ? AND index_value %s ? AND index_value %s ?",
251+
lowerBoundOp, upperBoundOp);
252+
bingArgs[i * 3] = indexId;
253+
bingArgs[i * 3 + 1] = value1;
254+
bingArgs[i * 3 + 2] = value2;
242255
++i;
243256
}
244257
}
245-
return new BindArgs(TextUtils.join(" OR ", filters), bingArgs);
258+
String sql = TextUtils.join(" UNION ", statements);
259+
return db.query(sql).binding(bingArgs);
246260
}
247261

248262
/**
@@ -378,15 +392,4 @@ private boolean isMultiValueFilter(Target target, FieldPath fieldPath) {
378392
private byte[] encodeFieldIndex(FieldIndex fieldIndex) {
379393
return serializer.encodeFieldIndex(fieldIndex).toByteArray();
380394
}
381-
382-
/** Stores a SQL statement of filters and their corresponding bind arguments. */
383-
static class BindArgs {
384-
final String sql;
385-
final Object[] bindArgs;
386-
387-
BindArgs(String sql, Object[] bindArgs) {
388-
this.sql = sql;
389-
this.bindArgs = bindArgs;
390-
}
391-
}
392395
}

0 commit comments

Comments
 (0)