@@ -114,22 +114,20 @@ public function getByAncestorInStorage(int $storageId, int $folderId, int $fileI
114114
115115 $ path = $ root ['path ' ] === '' ? '' : $ root ['path ' ] . '/ ' ;
116116
117- $ qb ->selectDistinct ('* ' )
117+ $ qb ->selectDistinct ('f. * ' )
118118 ->from ('filecache ' , 'f ' )
119119 ->where ($ qb ->expr ()->like ('f.path ' , $ qb ->createNamedParameter ($ this ->connection ->escapeLikeParameter ($ path ) . '% ' )))
120120 ->andWhere ($ qb ->expr ()->eq ('f.storage ' , $ qb ->createNamedParameter ($ storageId )))
121- ->andWhere ($ qb ->expr ()->gt ('f.fileid ' , $ qb ->createNamedParameter ($ fileIdCursor , IQueryBuilder::PARAM_INT )));
121+ ->andWhere ($ qb ->expr ()->gt ('f.fileid ' , $ qb ->createNamedParameter ($ fileIdCursor , IQueryBuilder::PARAM_INT )))
122+ ->hintShardKey ('storage ' , $ storageId );
122123
123- if (!$ endToEndEncrypted ) {
124+ if (!$ endToEndEncrypted && $ this -> connection -> getShardDefinition ( ' filecache ' ) === null ) {
124125 // End to end encrypted files are descendants of a folder with encrypted=1
125- // Use a subquery to check the `encrypted` status of the parent folder
126- $ subQuery = $ this ->getQuery ()->select ('p.encrypted ' )
127- ->from ('filecache ' , 'p ' )
128- ->andWhere ($ qb ->expr ()->eq ('p.fileid ' , 'f.parent ' ))
129- ->getSQL ();
126+ // We can only do this inner join if the filecache table is not sharded
127+ $ qb ->innerJoin ('f ' , 'filecache ' , 'f2 ' , $ qb ->expr ()->eq ('f2.fileid ' , 'f.parent ' ));
130128
131129 $ qb ->andWhere (
132- $ qb ->expr ()->eq ($ qb -> createFunction ( sprintf ( ' (%s) ' , $ subQuery )) , $ qb ->createNamedParameter (0 , IQueryBuilder::PARAM_INT ))
130+ $ qb ->expr ()->eq (' f2.encrypted ' , $ qb ->createNamedParameter (0 , IQueryBuilder::PARAM_INT ))
133131 );
134132 }
135133
@@ -148,11 +146,42 @@ public function getByAncestorInStorage(int $storageId, int $folderId, int $fileI
148146 $ qb ->orderBy ('f.fileid ' , 'ASC ' );
149147 $ files = $ qb ->executeQuery ();
150148
151- while (
152- /** @var array */
153- $ row = $ files ->fetch ()
154- ) {
155- yield Cache::cacheEntryFromData ($ row , $ this ->mimeTypeLoader );
149+ if (!$ endToEndEncrypted && $ this ->connection ->getShardDefinition ('filecache ' ) !== null ) {
150+ // End to end encrypted files are descendants of a folder with encrypted=1
151+ // If the filecache table is sharded we need to check with a separate query if the parent is encrypted
152+ $ rows = [];
153+ do {
154+ while (count ($ rows ) < 1000 && ($ row = $ files ->fetch ())) {
155+ $ rows [] = $ row ;
156+ }
157+ $ parents = array_map (function ($ row ) {
158+ return $ row ['parent ' ];
159+ }, $ rows );
160+
161+ $ parentQuery = $ this ->getQuery ();
162+ $ parentQuery ->select ('fileid ' , 'encrypted ' )->from ('filecache ' );
163+ $ parentQuery ->where ($ parentQuery ->expr ()->in ('fileid ' , $ parentQuery ->createNamedParameter ($ parents , IQueryBuilder::PARAM_INT_ARRAY )));
164+ $ parentQuery ->hintShardKey ('storage ' , $ storageId );
165+ $ result = $ parentQuery ->executeQuery ();
166+ $ parentRows = $ result ->fetchAll ();
167+ $ result ->closeCursor ();
168+
169+ $ encryptedByFileId = array_column ($ parentRows , 'encrypted ' , 'fileid ' );
170+ foreach ($ rows as $ row ) {
171+ if ($ encryptedByFileId [$ row ['parent ' ]]) {
172+ continue ;
173+ }
174+ yield Cache::cacheEntryFromData ($ row , $ this ->mimeTypeLoader );
175+ }
176+ $ rows = [];
177+ } while ($ rows [] = $ files ->fetch ());
178+ } else {
179+ while (
180+ /** @var array */
181+ $ row = $ files ->fetch ()
182+ ) {
183+ yield Cache::cacheEntryFromData ($ row , $ this ->mimeTypeLoader );
184+ }
156185 }
157186
158187 $ files ->closeCursor ();
0 commit comments