@@ -311,17 +311,7 @@ public function insert($file, array $data) {
311311 if ($ builder ->executeStatement ()) {
312312 $ fileId = $ builder ->getLastInsertId ();
313313
314- if (count ($ extensionValues )) {
315- $ query = $ this ->getQueryBuilder ();
316- $ query ->insert ('filecache_extended ' );
317- $ query ->hintShardKey ('storage ' , $ storageId );
318-
319- $ query ->setValue ('fileid ' , $ query ->createNamedParameter ($ fileId , IQueryBuilder::PARAM_INT ));
320- foreach ($ extensionValues as $ column => $ value ) {
321- $ query ->setValue ($ column , $ query ->createNamedParameter ($ value ));
322- }
323- $ query ->executeStatement ();
324- }
314+ $ this ->setExtensionValues ($ fileId , $ extensionValues , true );
325315
326316 $ event = new CacheEntryInsertedEvent ($ this ->storage , $ file , $ fileId , $ storageId );
327317 $ this ->eventDispatcher ->dispatch (CacheInsertEvent::class, $ event );
@@ -388,48 +378,82 @@ public function update($id, array $data) {
388378 $ query ->executeStatement ();
389379 }
390380
391- if (count ($ extensionValues )) {
392- try {
393- $ query = $ this ->getQueryBuilder ();
394- $ query ->insert ('filecache_extended ' );
395- $ query ->hintShardKey ('storage ' , $ this ->getNumericStorageId ());
381+ $ this ->setExtensionValues ($ id , $ extensionValues , false );
396382
397- $ query ->setValue ('fileid ' , $ query ->createNamedParameter ($ id , IQueryBuilder::PARAM_INT ));
398- foreach ($ extensionValues as $ column => $ value ) {
399- $ query ->setValue ($ column , $ query ->createNamedParameter ($ value ));
400- }
383+ $ path = $ this ->getPathById ($ id );
384+ // path can still be null if the file doesn't exist
385+ if ($ path !== null ) {
386+ $ event = new CacheEntryUpdatedEvent ($ this ->storage , $ path , $ id , $ this ->getNumericStorageId ());
387+ $ this ->eventDispatcher ->dispatch (CacheUpdateEvent::class, $ event );
388+ $ this ->eventDispatcher ->dispatchTyped ($ event );
389+ }
390+ }
401391
402- $ query ->executeStatement ();
392+ private function hasExtensionValues (int $ id ) {
393+ $ query = $ this ->getQueryBuilder ();
394+ $ query ->select ('fileid ' )
395+ ->from ('filecache_extended ' )
396+ ->whereFileId ($ id );
397+
398+ return $ query ->executeQuery ()->fetchOne () !== false ;
399+ }
400+
401+ private function setExtensionValues (int $ id , array $ extensionValues , bool $ newFile ) {
402+ if (!$ extensionValues ) {
403+ return ;
404+ }
405+
406+ // a failed insert in a transaction aborts the transactions on some platforms, so we can't rely on
407+ // that behavior to to an "upsert"
408+ // for new files, we can safely assume that there won't be a conflict, since the fileid is new
409+ if (!$ newFile && $ this ->connection ->inTransaction ()) {
410+ if ($ this ->hasExtensionValues ($ id )) {
411+ $ this ->updateExtensionValues ($ id , $ extensionValues );
412+ } else {
413+ $ this ->insertExtensionValues ($ id , $ extensionValues );
414+ }
415+ } else {
416+ try {
417+ $ this ->insertExtensionValues ($ id , $ extensionValues );
403418 } catch (Exception $ e ) {
404419 if ($ e ->getReason () !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION ) {
405420 throw $ e ;
406421 }
407- $ query = $ this ->getQueryBuilder ();
408- $ query ->update ('filecache_extended ' )
409- ->whereFileId ($ id )
410- ->hintShardKey ('storage ' , $ this ->getNumericStorageId ())
411- ->andWhere ($ query ->expr ()->orX (...array_map (function ($ key , $ value ) use ($ query ) {
412- return $ query ->expr ()->orX (
413- $ query ->expr ()->neq ($ key , $ query ->createNamedParameter ($ value )),
414- $ query ->expr ()->isNull ($ key )
415- );
416- }, array_keys ($ extensionValues ), array_values ($ extensionValues ))));
417-
418- foreach ($ extensionValues as $ key => $ value ) {
419- $ query ->set ($ key , $ query ->createNamedParameter ($ value ));
420- }
421-
422- $ query ->executeStatement ();
422+ $ this ->updateExtensionValues ($ id , $ extensionValues );
423423 }
424424 }
425+ }
425426
426- $ path = $ this ->getPathById ($ id );
427- // path can still be null if the file doesn't exist
428- if ($ path !== null ) {
429- $ event = new CacheEntryUpdatedEvent ($ this ->storage , $ path , $ id , $ this ->getNumericStorageId ());
430- $ this ->eventDispatcher ->dispatch (CacheUpdateEvent::class, $ event );
431- $ this ->eventDispatcher ->dispatchTyped ($ event );
427+ private function insertExtensionValues (int $ id , array $ extensionValues ) {
428+ $ query = $ this ->getQueryBuilder ();
429+ $ query ->insert ('filecache_extended ' );
430+ $ query ->hintShardKey ('storage ' , $ this ->getNumericStorageId ());
431+
432+ $ query ->setValue ('fileid ' , $ query ->createNamedParameter ($ id , IQueryBuilder::PARAM_INT ));
433+ foreach ($ extensionValues as $ column => $ value ) {
434+ $ query ->setValue ($ column , $ query ->createNamedParameter ($ value ));
435+ }
436+
437+ $ query ->executeStatement ();
438+ }
439+
440+ private function updateExtensionValues (int $ id , array $ extensionValues ) {
441+ $ query = $ this ->getQueryBuilder ();
442+ $ query ->update ('filecache_extended ' )
443+ ->whereFileId ($ id )
444+ ->hintShardKey ('storage ' , $ this ->getNumericStorageId ())
445+ ->andWhere ($ query ->expr ()->orX (...array_map (function ($ key , $ value ) use ($ query ) {
446+ return $ query ->expr ()->orX (
447+ $ query ->expr ()->neq ($ key , $ query ->createNamedParameter ($ value )),
448+ $ query ->expr ()->isNull ($ key )
449+ );
450+ }, array_keys ($ extensionValues ), array_values ($ extensionValues ))));
451+
452+ foreach ($ extensionValues as $ key => $ value ) {
453+ $ query ->set ($ key , $ query ->createNamedParameter ($ value ));
432454 }
455+
456+ $ query ->executeStatement ();
433457 }
434458
435459 /**
0 commit comments