@@ -240,31 +240,38 @@ private SQLitePersistence.Query generateQuery(
240
240
String lowerBoundOp ,
241
241
@ Nullable Object [] upperBounds ,
242
242
String upperBoundOp ) {
243
+ // The number of total statements we union together. This is similar to a distributed normal
244
+ // form, but adapted for array values. We create a single statement per value in an
245
+ // ARRAY_CONTAINS or ARRAY_CONTAINS_ANY filter combined with the values from the query bounds.
243
246
int statementCount =
244
247
max (arrayValues .size (), 1 )
245
248
* lowerBounds .length
246
249
* (upperBounds == null ? 1 : upperBounds .length );
250
+ // The number of "question marks" per single statement
247
251
int bindsPerStatement = 2 + (arrayValues .isEmpty () ? 0 : 1 ) + (upperBounds != null ? 1 : 0 );
248
252
Object [] bindArgs = new Object [statementCount * bindsPerStatement ];
249
253
254
+ // Build the statement. We always include the lower bound, and optionally include an array value
255
+ // and an upper bound.
250
256
StringBuilder statement = new StringBuilder ();
251
257
statement .append (
252
258
"SELECT document_name, directional_value FROM index_entries WHERE index_id = ? " );
253
- if (!arrayValues .isEmpty ()) {
254
- statement .append ("AND array_value = ? " );
255
- }
259
+ statement .append (arrayValues .isEmpty () ? "AND array_value IS NULL " : "AND array_value = ? " );
256
260
statement .append ("AND directional_value " ).append (lowerBoundOp ).append (" ? " );
257
261
if (upperBounds != null ) {
258
262
statement .append ("AND directional_value " ).append (upperBoundOp ).append (" ? " );
259
263
}
260
264
265
+ // Create the UNION statement by repeating the above generated statement. We can then add
266
+ // ordering and a limit clause.
261
267
String sql = repeatSequence (statement , statementCount , " UNION " );
262
268
if (target .getLimit () != -1 ) {
263
269
String direction = target .getFirstOrderBy ().getDirection ().canonicalString ();
264
270
sql += "ORDER BY directional_value " + direction + ", document_name " + direction + " " ;
265
271
sql += "LIMIT " + target .getLimit () + " " ;
266
272
}
267
273
274
+ // Fill in the bind ("question marks") variables.
268
275
Iterator <Value > arrayValueIterator = arrayValues .iterator ();
269
276
for (int offset = 0 ; offset < bindArgs .length ; ) {
270
277
Object arrayValue = encode (arrayValueIterator .hasNext () ? arrayValueIterator .next () : null );
@@ -282,6 +289,7 @@ private int fillBounds(
282
289
@ Nullable Object arrayValue ,
283
290
Object [] lowerBounds ,
284
291
@ Nullable Object [] upperBounds ) {
292
+ // Add bind variables for each combination of arrayValue, lowerBound and upperBound.
285
293
for (Object lower : lowerBounds ) {
286
294
for (int i = 0 ; i < (upperBounds != null ? upperBounds .length : 1 ); ++i ) {
287
295
bindArgs [offset ++] = indexId ;
0 commit comments