diff options
author | Joas Schilling <nickvergessen@gmx.de> | 2015-01-14 11:57:26 +0100 |
---|---|---|
committer | Joas Schilling <nickvergessen@gmx.de> | 2015-01-14 16:49:25 +0100 |
commit | a22068cce3c0681e51e02965a03e2372518cd172 (patch) | |
tree | a666eea5714cf11368f9b211e996a41ad0727061 /lib/repair | |
parent | 65ee2b1de88e490672067257a6a704a697d71e1e (diff) | |
download | nextcloud-server-a22068cce3c0681e51e02965a03e2372518cd172.tar.gz nextcloud-server-a22068cce3c0681e51e02965a03e2372518cd172.zip |
Add a repair step to clean up orphan tags and tag entries
Diffstat (limited to 'lib/repair')
-rw-r--r-- | lib/repair/cleantags.php | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/lib/repair/cleantags.php b/lib/repair/cleantags.php new file mode 100644 index 00000000000..6aa325df0b6 --- /dev/null +++ b/lib/repair/cleantags.php @@ -0,0 +1,114 @@ +<?php +/** + * Copyright (c) 2015 Joas Schilling <nickvergessen@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Repair; + +use OC\DB\Connection; +use OC\Hooks\BasicEmitter; +use OC\RepairStep; + +/** + * Class RepairConfig + * + * @package OC\Repair + */ +class CleanTags extends BasicEmitter implements RepairStep { + + /** @var Connection */ + protected $connection; + + /** + * @param Connection $connection + */ + public function __construct(Connection $connection) { + $this->connection = $connection; + } + + /** + * @return string + */ + public function getName() { + return 'Clean tags and favorites'; + } + + /** + * Updates the configuration after running an update + */ + public function run() { + + // Delete tag entries for deleted files + $this->deleteOrphanEntries( + '%d tags for delete files have been removed.', + '*PREFIX*vcategory_to_object', 'objid', + '*PREFIX*filecache', 'fileid', 'fileid' + ); + + // Delete tag entries for deleted tags + $this->deleteOrphanEntries( + '%d tag entries for deleted tags have been removed.', + '*PREFIX*vcategory_to_object', 'categoryid', + '*PREFIX*vcategory', 'id', 'uid' + ); + + // Delete tags that have no entries + $this->deleteOrphanEntries( + '%d tags with no entries have been removed.', + '*PREFIX*vcategory', 'id', + '*PREFIX*vcategory_to_object', 'categoryid', 'type' + ); + } + + /** + * Deletes all entries from $deleteTable that do not have a matching entry in $sourceTable + * + * A query joins $deleteTable.$deleteId = $sourceTable.$sourceId and checks + * whether $sourceNullColumn is null. If it is null, the entry in $deleteTable + * is being deleted. + * + * @param string $repairInfo + * @param string $deleteTable + * @param string $deleteId + * @param string $sourceTable + * @param string $sourceId + * @param string $sourceNullColumn If this column is null in the source table, + * the entry is deleted in the $deleteTable + */ + protected function deleteOrphanEntries($repairInfo, $deleteTable, $deleteId, $sourceTable, $sourceId, $sourceNullColumn) { + $qb = $this->connection->createQueryBuilder(); + + $qb->select('d.' . $deleteId) + ->from($deleteTable, 'd') + ->leftJoin('d', $sourceTable, 's', 'd.' . $deleteId . ' = s.' . $sourceId) + ->where( + 'd.type = ' . $qb->expr()->literal('files') + ) + ->andWhere( + $qb->expr()->isNull('s.' . $sourceNullColumn) + ); + $result = $qb->execute(); + + $orphanItems = array(); + while ($row = $result->fetch()) { + $orphanItems[] = (int) $row[$deleteId]; + } + + if (!empty($orphanItems)) { + $orphanItemsBatch = array_chunk($orphanItems, 200); + foreach ($orphanItemsBatch as $items) { + $qb->delete($deleteTable) + ->where($qb->expr()->in($deleteId, ':ids')); + $qb->setParameter('ids', $items, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY); + $qb->execute(); + } + } + + if ($repairInfo) { + $this->emit('\OC\Repair', 'info', array(sprintf($repairInfo, sizeof($orphanItems)))); + } + } +} |