DbRepository: Remove COLLATE from a query column in case of a pgsql connection

refs #8826
This commit is contained in:
Johannes Meyer 2015-05-27 11:47:18 +02:00
parent e55d43418d
commit 23b7ab0764
1 changed files with 85 additions and 0 deletions

View File

@ -64,14 +64,72 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
*/ */
protected $statementColumnMap; protected $statementColumnMap;
/**
* List of columns 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;
/** /**
* Create a new DB repository object * Create a new DB repository object
* *
* In case $this->queryColumns has already been initialized, this initializes
* $this->columnsWithoutCollation in case of a PostgreSQL connection.
*
* @param DbConnection $ds The datasource to use * @param DbConnection $ds The datasource to use
*/ */
public function __construct(DbConnection $ds) public function __construct(DbConnection $ds)
{ {
parent::__construct($ds); parent::__construct($ds);
$this->columnsWithoutCollation = array();
if ($ds->getDbType() === 'pgsql' && $this->queryColumns !== null) {
$this->queryColumns = $this->removeCollateInstruction($this->queryColumns);
}
}
/**
* Return the query columns being provided
*
* Initializes $this->columnsWithoutCollation in case of a PostgreSQL connection.
*
* @return array
*/
public function getQueryColumns()
{
if ($this->queryColumns === null) {
$this->queryColumns = parent::getQueryColumns();
if ($this->ds->getDbType() === 'pgsql') {
$this->queryColumns = $this->removeCollateInstruction($this->queryColumns);
}
}
return $this->queryColumns;
}
/**
* Remove each COLLATE SQL-instruction from all given query columns
*
* @param array $queryColumns
*
* @return array $queryColumns, the updated version
*/
protected function removeCollateInstruction($queryColumns)
{
foreach ($queryColumns as & $columns) {
foreach ($columns as & $column) {
$column = preg_replace('/ COLLATE .+$/', '', $column, -1, $count);
if ($count > 0) {
$this->columnsWithoutCollation[] = $column;
}
}
}
return $queryColumns;
} }
/** /**
@ -281,6 +339,33 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
return $this->prependTablePrefix($table); return $this->prependTablePrefix($table);
} }
/**
* Recurse the given filter, require each column for the given table and convert all values
*
* In case of a PostgreSQL connection, this applies LOWER() on the column and strtolower()
* on the value if a COLLATE SQL-instruction is part of the resolved column.
*
* @param string $table
* @param Filter $filter
*/
public function requireFilter($table, Filter $filter)
{
parent::requireFilter($table, $filter);
if ($filter->isExpression()) {
$column = $filter->getColumn();
if (in_array($column, $this->columnsWithoutCollation) && strpos($column, 'LOWER') !== 0) {
$filter->setColumn('LOWER(' . $column . ')');
$expression = $filter->getExpression();
if (is_array($expression)) {
$filter->setExpression(array_map('strtolower', $expression));
} else {
$filter->setExpression(strtolower($expression));
}
}
}
}
/** /**
* Return this repository's query columns of the given table mapped to their respective aliases * Return this repository's query columns of the given table mapped to their respective aliases
* *