Skip to content

Commit

Permalink
[Improvement] Prevent db errors on index updates on classes rebuild (#…
Browse files Browse the repository at this point in the history
…16871)

* [db-errors] check if index exists, before adding or remove it

* [db-errors] fix php code style by removing that foreach construct

* [db-errors] use caps for SQL syntax

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* [db-errors] use $indexName instead of $columnName, because $columnName can contain quotes

* [db-errors] fix typing of index exists db return value

* [db-errors] refactor some $columnName variable to $indexName

* [db-errors] chore: remove unused imports

---------

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>
  • Loading branch information
lukadschaak and jdreesen committed May 3, 2024
1 parent 9b560dc commit fa5c318
Showing 1 changed file with 33 additions and 14 deletions.
47 changes: 33 additions & 14 deletions models/DataObject/ClassDefinition/Helper/Dao.php
Expand Up @@ -15,8 +15,6 @@

namespace Pimcore\Model\DataObject\ClassDefinition\Helper;

use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Pimcore\Db\Helper;
use Pimcore\Model\DataObject;

/**
Expand Down Expand Up @@ -52,9 +50,9 @@ protected function addIndexToField(DataObject\ClassDefinition\Data $field, strin
$columnName .= ',`fieldname`';
}
}
Helper::queryIgnoreError($this->db, 'ALTER TABLE `'.$table.'` ADD ' . $uniqueStr . 'INDEX `' . $prefix . $indexName.'` ('.$columnName.');',
[UniqueConstraintViolationException::class]
);
if ($this->indexDoesNotExist($table, $prefix, $indexName)) {
$this->db->executeQuery('ALTER TABLE `' . $table . '` ADD ' . $uniqueStr . 'INDEX `' . $prefix . $indexName . '` (' . $columnName . ');');
}
}
} else {
// single -column field
Expand All @@ -67,21 +65,25 @@ protected function addIndexToField(DataObject\ClassDefinition\Data $field, strin
$columnName .= ',`fieldname`';
}
}
Helper::queryIgnoreError($this->db, 'ALTER TABLE `'.$table.'` ADD ' . $uniqueStr . 'INDEX `' . $prefix . $indexName.'` ('.$columnName.');',
[UniqueConstraintViolationException::class]
);
if ($this->indexDoesNotExist($table, $prefix, $indexName)) {
$this->db->executeQuery('ALTER TABLE `' . $table . '` ADD ' . $uniqueStr . 'INDEX `' . $prefix . $indexName . '` (' . $columnName . ');');
}
}
} else {
if (is_array($columnType)) {
// multicolumn field
foreach ($columnType as $fkey => $fvalue) {
$columnName = $field->getName().'__'.$fkey;
Helper::queryIgnoreError($this->db, 'ALTER TABLE `'.$table.'` DROP INDEX `'. $prefix . $columnName.'`;');
$indexName = $field->getName().'__'.$fkey;
if ($this->indexExists($table, $prefix, $indexName)) {
$this->db->executeQuery('ALTER TABLE `' . $table . '` DROP INDEX `' . $prefix . $indexName . '`;');
}
}
} else {
// single -column field
$columnName = $field->getName();
Helper::queryIgnoreError($this->db, 'ALTER TABLE `'.$table.'` DROP INDEX `'. $prefix . $columnName.'`;');
$indexName = $field->getName();
if ($this->indexExists($table, $prefix, $indexName)) {
$this->db->executeQuery('ALTER TABLE `' . $table . '` DROP INDEX `' . $prefix . $indexName . '`;');
}
}
}
}
Expand Down Expand Up @@ -172,11 +174,28 @@ protected function removeIndices(string $table, array $columnsToRemove, array $p
if ($columnsToRemove) {
$lowerCaseColumns = array_map('strtolower', $protectedColumns);
foreach ($columnsToRemove as $value) {
if (!in_array(strtolower($value), $lowerCaseColumns)) {
Helper::queryIgnoreError($this->db, 'ALTER TABLE `'.$table.'` DROP INDEX `u_index_'. $value . '`;');
if (!in_array(strtolower($value), $lowerCaseColumns) && $this->indexExists($table, 'u_index_', $value)) {
$this->db->executeQuery('ALTER TABLE `'.$table.'` DROP INDEX `u_index_'. $value . '`;');
}
}
$this->resetValidTableColumnsCache($table);
}
}

/**
* For MariaDB, it would be possible to use 'ADD/DROP INDEX IF EXISTS' but this is not supported by MySQL
*/
protected function indexExists(string $table, string $prefix, mixed $indexName): bool
{
$exist = $this->db->fetchFirstColumn(
"SELECT COUNT(*) FROM information_schema.statistics WHERE table_name = '${table}' AND index_name = '${prefix}${indexName}' AND table_schema = DATABASE();"
);

return (\count($exist) > 0) && (1 === $exist[0]);
}

protected function indexDoesNotExist(string $table, string $prefix, mixed $indexName): bool
{
return !$this->indexExists($table, $prefix, $indexName);
}
}

0 comments on commit fa5c318

Please sign in to comment.