Merge pull request #51197 from nextcloud/fix/51022/simpler-request-pre-upgrade

[stable31] fix(userconfig): simpler db request pre-upgrade
pull/51223/head
Andy Scherzinger 2025-03-04 13:11:20 +07:00 committed by GitHub
commit eb250fae02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 99 additions and 49 deletions

@ -64,6 +64,7 @@ class UserConfig implements IUserConfig {
private array $lazyLoaded = []; private array $lazyLoaded = [];
/** @var array<array-key, array{entries: array<array-key, ConfigLexiconEntry>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */ /** @var array<array-key, array{entries: array<array-key, ConfigLexiconEntry>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */
private array $configLexiconDetails = []; private array $configLexiconDetails = [];
private bool $upgradedTo31 = false;
public function __construct( public function __construct(
protected IDBConnection $connection, protected IDBConnection $connection,
@ -351,8 +352,12 @@ class UserConfig implements IUserConfig {
$this->assertParams('', $app, $key, allowEmptyUser: true); $this->assertParams('', $app, $key, allowEmptyUser: true);
$qb = $this->connection->getQueryBuilder(); $qb = $this->connection->getQueryBuilder();
$qb->select('userid', 'configvalue', 'type') if ($this->isUpgradedTo31()) {
->from('preferences') $qb->select('userid', 'configvalue', 'type');
} else {
$qb->select('userid', 'configvalue');
}
$qb->from('preferences')
->where($qb->expr()->eq('appid', $qb->createNamedParameter($app))) ->where($qb->expr()->eq('appid', $qb->createNamedParameter($app)))
->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key))); ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key)));
@ -363,7 +368,7 @@ class UserConfig implements IUserConfig {
while ($row = $result->fetch()) { while ($row = $result->fetch()) {
$value = $row['configvalue']; $value = $row['configvalue'];
try { try {
$value = $this->convertTypedValue($value, $typedAs ?? ValueType::from((int)$row['type'])); $value = $this->convertTypedValue($value, $typedAs ?? ValueType::from((int)($row['type'] ?? 0)));
} catch (IncorrectTypeException) { } catch (IncorrectTypeException) {
} }
$values[$row['userid']] = $value; $values[$row['userid']] = $value;
@ -471,34 +476,42 @@ class UserConfig implements IUserConfig {
$qb->where($qb->expr()->eq('appid', $qb->createNamedParameter($app))); $qb->where($qb->expr()->eq('appid', $qb->createNamedParameter($app)));
$qb->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key))); $qb->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key)));
// search within 'indexed' OR 'configvalue' only if 'flags' is set as not indexed
// TODO: when implementing config lexicon remove the searches on 'configvalue' if value is set as indexed
$configValueColumn = ($this->connection->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) ? $qb->expr()->castColumn('configvalue', IQueryBuilder::PARAM_STR) : 'configvalue'; $configValueColumn = ($this->connection->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) ? $qb->expr()->castColumn('configvalue', IQueryBuilder::PARAM_STR) : 'configvalue';
if (is_array($value)) { if ($this->isUpgradedTo31()) {
$where = $qb->expr()->orX( // search within 'indexed' OR 'configvalue' only if 'flags' is set as not indexed
$qb->expr()->in('indexed', $qb->createNamedParameter($value, IQueryBuilder::PARAM_STR_ARRAY)), // TODO: when implementing config lexicon remove the searches on 'configvalue' if value is set as indexed
$qb->expr()->andX( if (is_array($value)) {
$qb->expr()->neq($qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), $qb->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)),
$qb->expr()->in($configValueColumn, $qb->createNamedParameter($value, IQueryBuilder::PARAM_STR_ARRAY))
)
);
} else {
if ($caseInsensitive) {
$where = $qb->expr()->orX( $where = $qb->expr()->orX(
$qb->expr()->eq($qb->func()->lower('indexed'), $qb->createNamedParameter(strtolower($value))), $qb->expr()->in('indexed', $qb->createNamedParameter($value, IQueryBuilder::PARAM_STR_ARRAY)),
$qb->expr()->andX( $qb->expr()->andX(
$qb->expr()->neq($qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), $qb->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)), $qb->expr()->neq($qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), $qb->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)),
$qb->expr()->eq($qb->func()->lower($configValueColumn), $qb->createNamedParameter(strtolower($value))) $qb->expr()->in($configValueColumn, $qb->createNamedParameter($value, IQueryBuilder::PARAM_STR_ARRAY))
) )
); );
} else { } else {
$where = $qb->expr()->orX( if ($caseInsensitive) {
$qb->expr()->eq('indexed', $qb->createNamedParameter($value)), $where = $qb->expr()->orX(
$qb->expr()->andX( $qb->expr()->eq($qb->func()->lower('indexed'), $qb->createNamedParameter(strtolower($value))),
$qb->expr()->neq($qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), $qb->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)), $qb->expr()->andX(
$qb->expr()->eq($configValueColumn, $qb->createNamedParameter($value)) $qb->expr()->neq($qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), $qb->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)),
) $qb->expr()->eq($qb->func()->lower($configValueColumn), $qb->createNamedParameter(strtolower($value)))
); )
);
} else {
$where = $qb->expr()->orX(
$qb->expr()->eq('indexed', $qb->createNamedParameter($value)),
$qb->expr()->andX(
$qb->expr()->neq($qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), $qb->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)),
$qb->expr()->eq($configValueColumn, $qb->createNamedParameter($value))
)
);
}
}
} else {
if ($caseInsensitive) {
$where = $qb->expr()->eq($qb->func()->lower($configValueColumn), $qb->createNamedParameter(strtolower($value)));
} else {
$where = $qb->expr()->eq($configValueColumn, $qb->createNamedParameter($value));
} }
} }
@ -1088,15 +1101,23 @@ class UserConfig implements IUserConfig {
*/ */
try { try {
$insert = $this->connection->getQueryBuilder(); $insert = $this->connection->getQueryBuilder();
$insert->insert('preferences') if ($this->isUpgradedTo31()) {
->setValue('userid', $insert->createNamedParameter($userId)) $insert->insert('preferences')
->setValue('appid', $insert->createNamedParameter($app)) ->setValue('userid', $insert->createNamedParameter($userId))
->setValue('lazy', $insert->createNamedParameter(($lazy) ? 1 : 0, IQueryBuilder::PARAM_INT)) ->setValue('appid', $insert->createNamedParameter($app))
->setValue('type', $insert->createNamedParameter($type->value, IQueryBuilder::PARAM_INT)) ->setValue('lazy', $insert->createNamedParameter(($lazy) ? 1 : 0, IQueryBuilder::PARAM_INT))
->setValue('flags', $insert->createNamedParameter($flags, IQueryBuilder::PARAM_INT)) ->setValue('type', $insert->createNamedParameter($type->value, IQueryBuilder::PARAM_INT))
->setValue('indexed', $insert->createNamedParameter($indexed)) ->setValue('flags', $insert->createNamedParameter($flags, IQueryBuilder::PARAM_INT))
->setValue('configkey', $insert->createNamedParameter($key)) ->setValue('indexed', $insert->createNamedParameter($indexed))
->setValue('configvalue', $insert->createNamedParameter($value)); ->setValue('configkey', $insert->createNamedParameter($key))
->setValue('configvalue', $insert->createNamedParameter($value));
} else {
$insert->insert('preferences')
->setValue('userid', $insert->createNamedParameter($userId))
->setValue('appid', $insert->createNamedParameter($app))
->setValue('configkey', $insert->createNamedParameter($key))
->setValue('configvalue', $insert->createNamedParameter($value));
}
$insert->executeStatement(); $insert->executeStatement();
$inserted = true; $inserted = true;
} catch (DBException $e) { } catch (DBException $e) {
@ -1146,16 +1167,23 @@ class UserConfig implements IUserConfig {
} }
$update = $this->connection->getQueryBuilder(); $update = $this->connection->getQueryBuilder();
$update->update('preferences') if ($this->isUpgradedTo31()) {
->set('configvalue', $update->createNamedParameter($value)) $update->update('preferences')
->set('lazy', $update->createNamedParameter(($lazy) ? 1 : 0, IQueryBuilder::PARAM_INT)) ->set('configvalue', $update->createNamedParameter($value))
->set('type', $update->createNamedParameter($type->value, IQueryBuilder::PARAM_INT)) ->set('lazy', $update->createNamedParameter(($lazy) ? 1 : 0, IQueryBuilder::PARAM_INT))
->set('flags', $update->createNamedParameter($flags, IQueryBuilder::PARAM_INT)) ->set('type', $update->createNamedParameter($type->value, IQueryBuilder::PARAM_INT))
->set('indexed', $update->createNamedParameter($indexed)) ->set('flags', $update->createNamedParameter($flags, IQueryBuilder::PARAM_INT))
->where($update->expr()->eq('userid', $update->createNamedParameter($userId))) ->set('indexed', $update->createNamedParameter($indexed))
->andWhere($update->expr()->eq('appid', $update->createNamedParameter($app))) ->where($update->expr()->eq('userid', $update->createNamedParameter($userId)))
->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key))); ->andWhere($update->expr()->eq('appid', $update->createNamedParameter($app)))
->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key)));
} else {
$update->update('preferences')
->set('configvalue', $update->createNamedParameter($value))
->where($update->expr()->eq('userid', $update->createNamedParameter($userId)))
->andWhere($update->expr()->eq('appid', $update->createNamedParameter($app)))
->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key)));
}
$update->executeStatement(); $update->executeStatement();
} }
@ -1668,14 +1696,20 @@ class UserConfig implements IUserConfig {
$qb = $this->connection->getQueryBuilder(); $qb = $this->connection->getQueryBuilder();
$qb->from('preferences'); $qb->from('preferences');
$qb->select('appid', 'configkey', 'configvalue', 'type', 'flags'); if ($this->isUpgradedTo31()) {
$qb->select('appid', 'configkey', 'configvalue', 'type', 'flags');
} else {
$qb->select('appid', 'configkey', 'configvalue');
}
$qb->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId))); $qb->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId)));
// we only need value from lazy when loadConfig does not specify it if ($this->isUpgradedTo31()) {
if ($lazy !== null) { // we only need value from lazy when loadConfig does not specify it
$qb->andWhere($qb->expr()->eq('lazy', $qb->createNamedParameter($lazy ? 1 : 0, IQueryBuilder::PARAM_INT))); if ($lazy !== null) {
} else { $qb->andWhere($qb->expr()->eq('lazy', $qb->createNamedParameter($lazy ? 1 : 0, IQueryBuilder::PARAM_INT)));
$qb->addSelect('lazy'); } else {
$qb->addSelect('lazy');
}
} }
$result = $qb->executeQuery(); $result = $qb->executeQuery();
@ -1954,4 +1988,20 @@ class UserConfig implements IUserConfig {
return $this->configLexiconDetails[$appId]; return $this->configLexiconDetails[$appId];
} }
/**
* This is a temporary method that MUST be removed on NC32/NC32+
* It seems that some apps might want to check user preferences before initiating
* the upgrade process resulting in locking instance.
*
* @return bool
*/
private function isUpgradedTo31(): bool {
if (!$this->upgradedTo31) {
$this->upgradedTo31 = (str_starts_with($this->config->getSystemValue('version'), '31.')
|| str_starts_with($this->config->getSystemValue('version'), '32.'));
}
return $this->upgradedTo31;
}
} }