From 22f966db43490471df2520571c186ea824274283 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 11 Nov 2015 15:06:18 +0100 Subject: [PATCH] DbRepository: Fix that PostgreSQL queries use LOWER() on non-CI columns refs #10364 refs #9954 --- library/Icinga/Repository/DbRepository.php | 35 +++++++++++++--------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/library/Icinga/Repository/DbRepository.php b/library/Icinga/Repository/DbRepository.php index 9292a208b..5c946d173 100644 --- a/library/Icinga/Repository/DbRepository.php +++ b/library/Icinga/Repository/DbRepository.php @@ -93,20 +93,20 @@ abstract class DbRepository extends Repository implements Extensible, Updatable, protected $statementColumnAliasMap; /** - * List of columns where the COLLATE SQL-instruction has been removed + * List of column names or aliases mapped to their table where the COLLATE SQL-instruction has been removed * * This list is being populated in case of a PostgreSQL backend only, * to ensure case-insensitive string comparison in WHERE clauses. * * @var array */ - protected $columnsWithoutCollation; + protected $caseInsensitiveColumns; /** * Create a new DB repository object * * In case $this->queryColumns has already been initialized, this initializes - * $this->columnsWithoutCollation in case of a PostgreSQL connection. + * $this->caseInsensitiveColumns in case of a PostgreSQL connection. * * @param DbConnection $ds The datasource to use */ @@ -114,7 +114,6 @@ abstract class DbRepository extends Repository implements Extensible, Updatable, { parent::__construct($ds); - $this->columnsWithoutCollation = array(); if ($ds->getDbType() === 'pgsql' && $this->queryColumns !== null) { $this->queryColumns = $this->removeCollateInstruction($this->queryColumns); } @@ -123,7 +122,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable, /** * Return the query columns being provided * - * Initializes $this->columnsWithoutCollation in case of a PostgreSQL connection. + * Initializes $this->caseInsensitiveColumns in case of a PostgreSQL connection. * * @return array */ @@ -174,11 +173,12 @@ abstract class DbRepository extends Repository implements Extensible, Updatable, */ protected function removeCollateInstruction($queryColumns) { - foreach ($queryColumns as & $columns) { - foreach ($columns as & $column) { + foreach ($queryColumns as $table => & $columns) { + foreach ($columns as $alias => & $column) { + // Using a regex here because COLLATE may occur anywhere in the string $column = preg_replace('/ COLLATE .+$/', '', $column, -1, $count); if ($count > 0) { - $this->columnsWithoutCollation[] = $column; + $this->caseInsensitiveColumns[$table][is_string($alias) ? $alias : $column] = true; } } } @@ -607,22 +607,29 @@ abstract class DbRepository extends Repository implements Extensible, Updatable, */ public function requireFilter($table, Filter $filter, RepositoryQuery $query = null, $clone = true) { - $filter = parent::requireFilter($table, $filter, $query, $clone); + if (! empty($this->caseInsensitiveColumns) && $filter->isExpression()) { + $alias = $filter->getColumn(); + if (! $this->validateQueryColumnAssociation($table, $alias)) { + $origin = $this->findTableName($alias); // It might be a joined column + } else { + $origin = $table; + } - if ($filter->isExpression()) { - $column = $filter->getColumn(); - if (in_array($column, $this->columnsWithoutCollation) && strpos($column, 'LOWER') !== 0) { - $filter->setColumn('LOWER(' . $column . ')'); + if ($origin && isset($this->caseInsensitiveColumns[$origin][$alias])) { + $filter = parent::requireFilter($table, $filter, $query, $clone); + $filter->setColumn('LOWER(' . $filter->getColumn() . ')'); $expression = $filter->getExpression(); if (is_array($expression)) { $filter->setExpression(array_map('strtolower', $expression)); } else { $filter->setExpression(strtolower($expression)); } + + return $filter; } } - return $filter; + return parent::requireFilter($table, $filter, $query, $clone); } /**