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
Loading
Pipeline #48729 passed
Pipeline: drupal

#48731

    ...@@ -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