Browse Source

Merge pull request #32069 from nextcloud/cleanup/allconfig-sql

Cleanup AllConfig
tags/v25.0.0beta1
Carl Schwan 2 years ago
parent
commit
59e0402691
No account linked to committer's email address
2 changed files with 64 additions and 78 deletions
  1. 64
    69
      lib/private/AllConfig.php
  2. 0
    9
      tests/lib/AllConfigTest.php

+ 64
- 69
lib/private/AllConfig.php View File

namespace OC; namespace OC;


use OC\Cache\CappedMemoryCache; use OC\Cache\CappedMemoryCache;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
use OCP\IDBConnection; use OCP\IDBConnection;
use OCP\PreConditionNotMetException; use OCP\PreConditionNotMetException;


/** /**
* Class to combine all the configuration options ownCloud offers * Class to combine all the configuration options ownCloud offers
*/ */
class AllConfig implements \OCP\IConfig {
/** @var SystemConfig */
private $systemConfig;

/** @var IDBConnection */
private $connection;
class AllConfig implements IConfig {
private SystemConfig $systemConfig;
private ?IDBConnection $connection = null;


/** /**
* 3 dimensional array with the following structure: * 3 dimensional array with the following structure:
* *
* @var CappedMemoryCache $userCache * @var CappedMemoryCache $userCache
*/ */
private $userCache;
private CappedMemoryCache $userCache;


/**
* @param SystemConfig $systemConfig
*/
public function __construct(SystemConfig $systemConfig) { public function __construct(SystemConfig $systemConfig) {
$this->userCache = new CappedMemoryCache(); $this->userCache = new CappedMemoryCache();
$this->systemConfig = $systemConfig; $this->systemConfig = $systemConfig;
*/ */
private function fixDIInit() { private function fixDIInit() {
if ($this->connection === null) { if ($this->connection === null) {
$this->connection = \OC::$server->getDatabaseConnection();
$this->connection = \OC::$server->get(IDBConnection::class);
} }
} }


* @return string[] the keys stored for the app * @return string[] the keys stored for the app
*/ */
public function getAppKeys($appName) { public function getAppKeys($appName) {
return \OC::$server->query(\OC\AppConfig::class)->getKeys($appName);
return \OC::$server->get(AppConfig::class)->getKeys($appName);
} }


/** /**
* @param string|float|int $value the value that should be stored * @param string|float|int $value the value that should be stored
*/ */
public function setAppValue($appName, $key, $value) { public function setAppValue($appName, $key, $value) {
\OC::$server->query(\OC\AppConfig::class)->setValue($appName, $key, $value);
\OC::$server->get(AppConfig::class)->setValue($appName, $key, $value);
} }


/** /**
* @return string the saved value * @return string the saved value
*/ */
public function getAppValue($appName, $key, $default = '') { public function getAppValue($appName, $key, $default = '') {
return \OC::$server->query(\OC\AppConfig::class)->getValue($appName, $key, $default);
return \OC::$server->get(AppConfig::class)->getValue($appName, $key, $default);
} }


/** /**
* @param string $key the key of the value, under which it was saved * @param string $key the key of the value, under which it was saved
*/ */
public function deleteAppValue($appName, $key) { public function deleteAppValue($appName, $key) {
\OC::$server->query(\OC\AppConfig::class)->deleteKey($appName, $key);
\OC::$server->get(AppConfig::class)->deleteKey($appName, $key);
} }


/** /**
* @param string $appName the appName the configs are stored under * @param string $appName the appName the configs are stored under
*/ */
public function deleteAppValues($appName) { public function deleteAppValues($appName) {
\OC::$server->query(\OC\AppConfig::class)->deleteApp($appName);
\OC::$server->get(AppConfig::class)->deleteApp($appName);
} }




->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId))) ->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId)))
->andWhere($qb->expr()->eq('appid', $qb->createNamedParameter($appName))) ->andWhere($qb->expr()->eq('appid', $qb->createNamedParameter($appName)))
->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key))); ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key)));
$qb->execute();
$qb->executeStatement();


$this->userCache[$userId][$appName][$key] = (string)$value; $this->userCache[$userId][$appName][$key] = (string)$value;
return; return;
// TODO - FIXME // TODO - FIXME
$this->fixDIInit(); $this->fixDIInit();


$sql = 'DELETE FROM `*PREFIX*preferences` '.
'WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?';
$this->connection->executeUpdate($sql, [$userId, $appName, $key]);
$qb = $this->connection->getQueryBuilder();
$qb->delete('preferences')
->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
->where($qb->expr()->eq('appid', $qb->createNamedParameter($appName, IQueryBuilder::PARAM_STR)))
->where($qb->expr()->eq('configkey', $qb->createNamedParameter($key, IQueryBuilder::PARAM_STR)))
->executeStatement();


if (isset($this->userCache[$userId][$appName])) { if (isset($this->userCache[$userId][$appName])) {
unset($this->userCache[$userId][$appName][$key]); unset($this->userCache[$userId][$appName][$key]);
public function deleteAllUserValues($userId) { public function deleteAllUserValues($userId) {
// TODO - FIXME // TODO - FIXME
$this->fixDIInit(); $this->fixDIInit();
$sql = 'DELETE FROM `*PREFIX*preferences` '.
'WHERE `userid` = ?';
$this->connection->executeUpdate($sql, [$userId]);
$qb = $this->connection->getQueryBuilder();
$qb->delete('preferences')
->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
->executeStatement();


unset($this->userCache[$userId]); unset($this->userCache[$userId]);
} }
// TODO - FIXME // TODO - FIXME
$this->fixDIInit(); $this->fixDIInit();


$sql = 'DELETE FROM `*PREFIX*preferences` '.
'WHERE `appid` = ?';
$this->connection->executeUpdate($sql, [$appName]);
$qb = $this->connection->getQueryBuilder();
$qb->delete('preferences')
->where($qb->expr()->eq('appid', $qb->createNamedParameter($appName, IQueryBuilder::PARAM_STR)))
->executeStatement();


foreach ($this->userCache as &$userCache) { foreach ($this->userCache as &$userCache) {
unset($userCache[$appName]); unset($userCache[$appName]);
$this->fixDIInit(); $this->fixDIInit();


$data = []; $data = [];
$query = 'SELECT `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?';
$result = $this->connection->executeQuery($query, [$userId]);

$qb = $this->connection->getQueryBuilder();
$result = $qb->select('appid', 'configkey', 'configvalue')
->from('preferences')
->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
->executeQuery();
while ($row = $result->fetch()) { while ($row = $result->fetch()) {
$appId = $row['appid']; $appId = $row['appid'];
if (!isset($data[$appId])) { if (!isset($data[$appId])) {
} }


$chunkedUsers = array_chunk($userIds, 50, true); $chunkedUsers = array_chunk($userIds, 50, true);
$placeholders50 = implode(',', array_fill(0, 50, '?'));

$qb = $this->connection->getQueryBuilder();
$qb->select('userid', 'configvalue')
->from('preferences')
->where($qb->expr()->eq('appid', $qb->createParameter('appName')))
->andWhere($qb->expr()->eq('configkey', $qb->createParameter('configKey')))
->andWhere($qb->expr()->in('userid', $qb->createParameter('userIds')));


$userValues = []; $userValues = [];
foreach ($chunkedUsers as $chunk) { foreach ($chunkedUsers as $chunk) {
$queryParams = $chunk;
// create [$app, $key, $chunkedUsers]
array_unshift($queryParams, $key);
array_unshift($queryParams, $appName);

$placeholders = (count($chunk) === 50) ? $placeholders50 : implode(',', array_fill(0, count($chunk), '?'));

$query = 'SELECT `userid`, `configvalue` ' .
'FROM `*PREFIX*preferences` ' .
'WHERE `appid` = ? AND `configkey` = ? ' .
'AND `userid` IN (' . $placeholders . ')';
$result = $this->connection->executeQuery($query, $queryParams);
$qb->setParameter('appName', $appName, IQueryBuilder::PARAM_STR);
$qb->setParameter('configKey', $key, IQueryBuilder::PARAM_STR);
$qb->setParameter('userIds', $chunk, IQueryBuilder::PARAM_STR_ARRAY);
$result = $qb->executeQuery();


while ($row = $result->fetch()) { while ($row = $result->fetch()) {
$userValues[$row['userid']] = $row['configvalue']; $userValues[$row['userid']] = $row['configvalue'];
// TODO - FIXME // TODO - FIXME
$this->fixDIInit(); $this->fixDIInit();


$sql = 'SELECT `userid` FROM `*PREFIX*preferences` ' .
'WHERE `appid` = ? AND `configkey` = ? ';

if ($this->getSystemValue('dbtype', 'sqlite') === 'oci') {
//oracle hack: need to explicitly cast CLOB to CHAR for comparison
$sql .= 'AND to_char(`configvalue`) = ?';
} else {
$sql .= 'AND `configvalue` = ?';
}

$sql .= ' ORDER BY `userid`';

$result = $this->connection->executeQuery($sql, [$appName, $key, $value]);
$qb = $this->connection->getQueryBuilder();
$result = $qb->select('userid')
->from('preferences')
->where($qb->expr()->eq('appid', $qb->createNamedParameter($appName, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq(
$qb->expr()->castColumn('configvalue', IQueryBuilder::PARAM_STR),
$qb->createNamedParameter($value, IQueryBuilder::PARAM_STR))
)->orderBy('userid')
->executeQuery();


$userIDs = []; $userIDs = [];
while ($row = $result->fetch()) { while ($row = $result->fetch()) {
// Email address is always stored lowercase in the database // Email address is always stored lowercase in the database
return $this->getUsersForUserValue($appName, $key, strtolower($value)); return $this->getUsersForUserValue($appName, $key, strtolower($value));
} }

$sql = 'SELECT `userid` FROM `*PREFIX*preferences` ' .
'WHERE `appid` = ? AND `configkey` = ? ';

if ($this->getSystemValue('dbtype', 'sqlite') === 'oci') {
//oracle hack: need to explicitly cast CLOB to CHAR for comparison
$sql .= 'AND LOWER(to_char(`configvalue`)) = ?';
} else {
$sql .= 'AND LOWER(`configvalue`) = ?';
}

$sql .= ' ORDER BY `userid`';

$result = $this->connection->executeQuery($sql, [$appName, $key, strtolower($value)]);
$qb = $this->connection->getQueryBuilder();
$result = $qb->select('userid')
->from('preferences')
->where($qb->expr()->eq('appid', $qb->createNamedParameter($appName, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq(
$qb->func()->lower($qb->expr()->castColumn('configvalue', IQueryBuilder::PARAM_STR)),
$qb->createNamedParameter(strtolower($value), IQueryBuilder::PARAM_STR))
)->orderBy('userid')
->executeQuery();


$userIDs = []; $userIDs = [];
while ($row = $result->fetch()) { while ($row = $result->fetch()) {

+ 0
- 9
tests/lib/AllConfigTest.php View File

$systemConfig = $this->getMockBuilder('\OC\SystemConfig') $systemConfig = $this->getMockBuilder('\OC\SystemConfig')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$systemConfig->expects($this->once())
->method('getValue')
->with($this->equalTo('dbtype'),
$this->equalTo('sqlite'))
->willReturn(\OC::$server->getConfig()->getSystemValue('dbtype', 'sqlite'));
$config = $this->getConfig($systemConfig); $config = $this->getConfig($systemConfig);


// preparation - add something to the database // preparation - add something to the database
public function testGetUsersForUserValueCaseInsensitive() { public function testGetUsersForUserValueCaseInsensitive() {
// mock the check for the database to run the correct SQL statements for each database type // mock the check for the database to run the correct SQL statements for each database type
$systemConfig = $this->createMock(SystemConfig::class); $systemConfig = $this->createMock(SystemConfig::class);
$systemConfig->expects($this->once())
->method('getValue')
->with($this->equalTo('dbtype'), $this->equalTo('sqlite'))
->willReturn(\OC::$server->getConfig()->getSystemValue('dbtype', 'sqlite'));
$config = $this->getConfig($systemConfig); $config = $this->getConfig($systemConfig);


$config->setUserValue('user1', 'myApp', 'myKey', 'test123'); $config->setUserValue('user1', 'myApp', 'myKey', 'test123');

Loading…
Cancel
Save