Skip to content
Snippets Groups Projects
Verified Commit f00184db authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3365945 by larowlan, sakthi_dev, alexpott, catch, daffie, mkimmet,...

Issue #3365945 by larowlan, sakthi_dev, alexpott, catch, daffie, mkimmet, Olarin, rakesh.gectcr, JvE, borisson_, eelkeblok: Errors: The following table(s) do not have a primary key: forum_index
parent 6514a929
No related branches found
No related tags found
No related merge requests found
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Install, update, and uninstall functions for the Forum module. * Install, update, and uninstall functions for the Forum module.
*/ */
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Drupal\field\Entity\FieldStorageConfig; use Drupal\field\Entity\FieldStorageConfig;
use Drupal\taxonomy\Entity\Term; use Drupal\taxonomy\Entity\Term;
...@@ -161,6 +162,7 @@ function forum_schema() { ...@@ -161,6 +162,7 @@ function forum_schema() {
'created' => ['created'], 'created' => ['created'],
'last_comment_timestamp' => ['last_comment_timestamp'], 'last_comment_timestamp' => ['last_comment_timestamp'],
], ],
'primary key' => ['nid', 'tid'],
'foreign keys' => [ 'foreign keys' => [
'tracked_node' => [ 'tracked_node' => [
'table' => 'node', 'table' => 'node',
...@@ -204,3 +206,39 @@ function forum_update_10100(&$sandbox = NULL) { ...@@ -204,3 +206,39 @@ function forum_update_10100(&$sandbox = NULL) {
$connection->schema()->changeField('forum_index', 'last_comment_timestamp', 'last_comment_timestamp', $new); $connection->schema()->changeField('forum_index', 'last_comment_timestamp', 'last_comment_timestamp', $new);
} }
} }
/**
* Repopulate the forum index table.
*/
function forum_update_10101(&$sandbox = NULL): PluralTranslatableMarkup {
$query = \Drupal::database()->select('forum_index', 'fi')
->fields('fi', ['nid', 'tid'])
->groupBy('nid')
->groupBy('tid');
$query->addExpression('count(*)', 'count');
$query->having('count(*) > 1');
$results = $query->execute();
$nids_to_rebuild = [];
foreach ($results as $row) {
\Drupal::database()->delete('forum_index')->condition('tid', $row->tid)->condition('nid', $row->nid)->execute();
$nids_to_rebuild[] = $row->nid;
}
\Drupal::state()->set('forum_update_10101_nids', $nids_to_rebuild);
return new PluralTranslatableMarkup(count($nids_to_rebuild), 'Removed 1 duplicate entry from forum_index', 'Removed @count duplicate entries from forum_index');
}
/**
* Add a primary key to forum_index.
*/
function forum_update_10102(&$sandbox = NULL) {
$connection = \Drupal::database();
if ($connection->schema()->tableExists('forum_index')) {
// Data in this table could have duplicates. The data can be re-constructed
// from other data in the site. To avoid duplicate key errors we delete any
// rows that are duplicates and then recreate them in a post-update hook.
// @see \forum_post_update_recreate_forum_index_rows().
$connection->schema()->addPrimaryKey('forum_index', ['nid', 'tid']);
return \t('Added primary key to the forum_index table.');
}
return \t('Index already exists');
}
<?php
/**
* @file
* Contains post update functions.
*/
use Drupal\Core\Site\Settings;
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\node\NodeInterface;
/**
* Repopulate the forum index table.
*/
function forum_post_update_recreate_forum_index_rows(&$sandbox = NULL): TranslatableMarkup {
$entityStorage = \Drupal::entityTypeManager()->getStorage('node');
if (!isset($sandbox['ids'])) {
// This must be the first run. Initialize the sandbox.
$sandbox['ids'] = \Drupal::state()->get('forum_update_10101_nids', []);
$sandbox['max'] = count($sandbox['ids']);
}
$ids = array_splice($sandbox['ids'], 0, (int) Settings::get('entity_update_batch_size', 50));
$insert = \Drupal::database()->insert('forum_index')->fields([
'nid',
'title',
'tid',
'sticky',
'created',
'last_comment_timestamp',
'comment_count',
]);
$do_insert = FALSE;
foreach ($entityStorage->loadMultiple($ids) as $entity) {
$do_insert = TRUE;
assert($entity instanceof NodeInterface);
$insert->values([
$entity->id(),
$entity->label(),
$entity->taxonomy_forums->target_id,
(int) $entity->isSticky(),
$entity->getCreatedTime(),
$entity->comment_forum->last_comment_timestamp,
$entity->comment_forum->comment_count,
]);
}
if ($do_insert) {
$insert->execute();
}
$sandbox['#finished'] = empty($sandbox['max']) || empty($sandbox['ids']) ? 1 : ($sandbox['max'] - count($sandbox['ids'])) / $sandbox['max'];
if ($sandbox['#finished'] === 1) {
\Drupal::state()->delete('forum_update_10101_nids');
return new TranslatableMarkup('Finished updating forum index rows.');
}
return new PluralTranslatableMarkup($sandbox['max'] - count($sandbox['ids']),
'Processed @count entry of @total.',
'Processed @count entries of @total.',
['@total' => $sandbox['max']],
);
}
This diff is collapsed.
<?php
declare(strict_types=1);
namespace Drupal\Tests\forum\Functional;
use Drupal\Core\Site\Settings;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
/**
* Tests addition of the forum_index primary key.
*
* @group forum
*/
final class ForumIndexUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
dirname(__DIR__, 2) . '/fixtures/update/drupal-10.1.0.empty.testing.forum.gz',
];
}
/**
* Tests the update path to add the new primary key.
*/
public function testUpdatePath(): void {
// Set the batch size to 1 to validate the sandbox logic in the update hook.
$settings = Settings::getInstance() ? Settings::getAll() : [];
$settings['entity_update_batch_size'] = 1;
new Settings($settings);
$schema = \Drupal::database()->schema();
// We can't reliably call ::indexExists for each database driver as sqlite
// doesn't have named indexes for primary keys like mysql (PRIMARY) and
// pgsql (pkey).
$find_primary_key_columns = new \ReflectionMethod(get_class($schema), 'findPrimaryKeyColumns');
$columns = $find_primary_key_columns->invoke($schema, 'forum_index');
$this->assertEmpty($columns);
$count = \Drupal::database()->select('forum_index')->countQuery()->execute()->fetchField();
$this->assertEquals(9, $count);
$duplicates = \Drupal::database()->select('forum_index')->condition('nid', 1)->countQuery()->execute()->fetchField();
$this->assertEquals(2, $duplicates);
$duplicates = \Drupal::database()->select('forum_index')->condition('nid', 2)->countQuery()->execute()->fetchField();
$this->assertEquals(3, $duplicates);
$this->runUpdates();
$this->assertEquals(['nid', 'tid'], $find_primary_key_columns->invoke($schema, 'forum_index'));
$count = \Drupal::database()->select('forum_index')->countQuery()->execute()->fetchField();
$this->assertEquals(6, $count);
$duplicates = \Drupal::database()->select('forum_index')->condition('nid', 1)->countQuery()->execute()->fetchField();
$this->assertEquals(1, $duplicates);
$duplicates = \Drupal::database()->select('forum_index')->condition('nid', 2)->countQuery()->execute()->fetchField();
$this->assertEquals(1, $duplicates);
// This entry is associated with two terms so two records should remain.
$duplicates = \Drupal::database()->select('forum_index')->condition('nid', 4)->countQuery()->execute()->fetchField();
$this->assertEquals(2, $duplicates);
$entry = \Drupal::database()->select('forum_index', 'f')->fields('f')->condition('nid', 5)->execute()->fetchAssoc();
$this->assertEquals([
'nid' => 5,
'title' => 'AFL',
'tid' => 5,
'sticky' => 0,
'created' => 1695264369,
'last_comment_timestamp' => 1695264403,
'comment_count' => 1,
], $entry);
}
}
<?php
declare(strict_types=1);
namespace Drupal\Tests\forum\Kernel;
use Drupal\KernelTests\KernelTestBase;
/**
* Defines a class for testing the forum_index table.
*
* @group forum
*/
final class ForumIndexTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'system',
'user',
'node',
'history',
'taxonomy',
'forum',
'comment',
'options',
'text',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('node');
$this->installEntitySchema('user');
$this->installEntitySchema('comment');
$this->installEntitySchema('taxonomy_term');
$this->installSchema('forum', ['forum_index']);
}
/**
* Tests there's a primary key on the forum_index table.
*/
public function testForumIndexIndex(): void {
$schema = \Drupal::database()->schema();
$this->assertTrue($schema->tableExists('forum_index'));
// We can't reliably call ::indexExists for each database driver as sqlite
// doesn't have named indexes for primary keys like mysql (PRIMARY) and
// pgsql (pkey).
$find_primary_key_columns = new \ReflectionMethod(get_class($schema), 'findPrimaryKeyColumns');
$this->assertEquals(['nid', 'tid'], $find_primary_key_columns->invoke($schema, 'forum_index'));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment