@@ -63,10 +63,10 @@ public void add(MutableDocument document, SnapshotVersion readTime) {
63
63
64
64
db .execute (
65
65
"INSERT OR REPLACE INTO remote_documents "
66
- + "(path, parent_path , read_time_seconds, read_time_nanos, contents) "
66
+ + "(path, path_length , read_time_seconds, read_time_nanos, contents) "
67
67
+ "VALUES (?, ?, ?, ?, ?)" ,
68
68
EncodedPath .encode (documentKey .getPath ()),
69
- EncodedPath . encode ( documentKey .getCollectionPath () ),
69
+ documentKey .getPath (). length ( ),
70
70
timestamp .getSeconds (),
71
71
timestamp .getNanoseconds (),
72
72
message .toByteArray ());
@@ -135,69 +135,73 @@ public ImmutableSortedMap<DocumentKey, MutableDocument> getAllDocumentsMatchingQ
135
135
!query .isCollectionGroupQuery (),
136
136
"CollectionGroup queries should be handled in LocalDocumentsView" );
137
137
138
- String parentPath = EncodedPath .encode (query .getPath ());
139
- BackgroundQueue backgroundQueue = new BackgroundQueue ();
138
+ StringBuilder sql =
139
+ new StringBuilder (
140
+ "SELECT contents, read_time_seconds, read_time_nanos "
141
+ + "FROM remote_documents WHERE path >= ? AND path < ? AND path_length = ?" );
140
142
141
- ImmutableSortedMap <DocumentKey , MutableDocument >[] matchingDocuments =
142
- (ImmutableSortedMap <DocumentKey , MutableDocument >[])
143
- new ImmutableSortedMap [] {DocumentCollections .emptyMutableDocumentMap ()};
143
+ Object [] bindVars = new Object [3 + (FieldIndex .IndexOffset .NONE .equals (offset ) ? 0 : 6 )];
144
144
145
- SQLitePersistence . Query sqlQuery ;
146
- if ( FieldIndex . IndexOffset . NONE . equals ( offset )) {
147
- sqlQuery =
148
- db . query (
149
- "SELECT contents, read_time_seconds, read_time_nanos "
150
- + "FROM remote_documents WHERE parent_path = ?" )
151
- . binding ( parentPath );
152
- } else {
145
+ String prefix = EncodedPath . encode ( query . getPath ()) ;
146
+
147
+ int i = 0 ;
148
+ bindVars [ i ++] = prefix ;
149
+ bindVars [ i ++] = EncodedPath . prefixSuccessor ( prefix );
150
+ bindVars [ i ++] = query . getPath (). length () + 1 ;
151
+
152
+ if (! FieldIndex . IndexOffset . NONE . equals ( offset )) {
153
153
Timestamp readTime = offset .getReadTime ().getTimestamp ();
154
154
DocumentKey documentKey = offset .getDocumentKey ();
155
155
156
- sqlQuery =
157
- db .query (
158
- "SELECT contents, read_time_seconds, read_time_nanos "
159
- + "FROM remote_documents WHERE parent_path = ? AND ("
160
- + "read_time_seconds > ? OR ("
161
- + "read_time_seconds = ? AND read_time_nanos > ?) OR ("
162
- + "read_time_seconds = ? AND read_time_nanos = ? and path > ?))" )
163
- .binding (
164
- parentPath ,
165
- readTime .getSeconds (),
166
- readTime .getSeconds (),
167
- readTime .getNanoseconds (),
168
- readTime .getSeconds (),
169
- readTime .getNanoseconds (),
170
- EncodedPath .encode (documentKey .getPath ()));
156
+ sql .append (
157
+ " AND (read_time_seconds > ? OR ("
158
+ + "read_time_seconds = ? AND read_time_nanos > ?) OR ("
159
+ + "read_time_seconds = ? AND read_time_nanos = ? and path > ?))" );
160
+ bindVars [i ++] = readTime .getSeconds ();
161
+ bindVars [i ++] = readTime .getSeconds ();
162
+ bindVars [i ++] = readTime .getNanoseconds ();
163
+ bindVars [i ++] = readTime .getSeconds ();
164
+ bindVars [i ++] = readTime .getNanoseconds ();
165
+ bindVars [i ] = EncodedPath .encode (documentKey .getPath ());
171
166
}
172
- sqlQuery .forEach (
173
- row -> {
174
- // Store row values in array entries to provide the correct context inside the executor.
175
- final byte [] rawDocument = row .getBlob (0 );
176
- final int [] readTimeSeconds = {row .getInt (1 )};
177
- final int [] readTimeNanos = {row .getInt (2 )};
178
-
179
- // Since scheduling background tasks incurs overhead, we only dispatch to a
180
- // background thread if there are still some documents remaining.
181
- Executor executor = row .isLast () ? Executors .DIRECT_EXECUTOR : backgroundQueue ;
182
- executor .execute (
183
- () -> {
184
- MutableDocument document =
185
- decodeMaybeDocument (rawDocument , readTimeSeconds [0 ], readTimeNanos [0 ]);
186
- if (document .isFoundDocument () && query .matches (document )) {
187
- synchronized (SQLiteRemoteDocumentCache .this ) {
188
- matchingDocuments [0 ] = matchingDocuments [0 ].insert (document .getKey (), document );
189
- }
190
- }
191
- });
192
- });
167
+
168
+ ImmutableSortedMap <DocumentKey , MutableDocument >[] results =
169
+ (ImmutableSortedMap <DocumentKey , MutableDocument >[])
170
+ new ImmutableSortedMap [] {DocumentCollections .emptyMutableDocumentMap ()};
171
+ BackgroundQueue backgroundQueue = new BackgroundQueue ();
172
+
173
+ db .query (sql .toString ())
174
+ .binding (bindVars )
175
+ .forEach (
176
+ row -> {
177
+ // Store row values in array entries to provide the correct context inside the
178
+ // executor.
179
+ final byte [] rawDocument = row .getBlob (0 );
180
+ final int [] readTimeSeconds = {row .getInt (1 )};
181
+ final int [] readTimeNanos = {row .getInt (2 )};
182
+
183
+ // Since scheduling background tasks incurs overhead, we only dispatch to a
184
+ // background thread if there are still some documents remaining.
185
+ Executor executor = row .isLast () ? Executors .DIRECT_EXECUTOR : backgroundQueue ;
186
+ executor .execute (
187
+ () -> {
188
+ MutableDocument document =
189
+ decodeMaybeDocument (rawDocument , readTimeSeconds [0 ], readTimeNanos [0 ]);
190
+ if (document .isFoundDocument () && query .matches (document )) {
191
+ synchronized (SQLiteRemoteDocumentCache .this ) {
192
+ results [0 ] = results [0 ].insert (document .getKey (), document );
193
+ }
194
+ }
195
+ });
196
+ });
193
197
194
198
try {
195
199
backgroundQueue .drain ();
196
200
} catch (InterruptedException e ) {
197
201
fail ("Interrupted while deserializing documents" , e );
198
202
}
199
203
200
- return matchingDocuments [0 ];
204
+ return results [0 ];
201
205
}
202
206
203
207
@ Override
0 commit comments