Skip to content

Commit 92d049d

Browse files
authored
Run fulltext index alters one at at time (#4288)
1 parent 62b7b79 commit 92d049d

File tree

3 files changed

+113
-4
lines changed

3 files changed

+113
-4
lines changed

modules/datastore/src/DataDictionary/AlterTableQuery/MySQLQuery.php

+30-1
Original file line numberDiff line numberDiff line change
@@ -514,12 +514,41 @@ protected function buildAddIndexOptions(array $indexes, string $table, array $ty
514514
$comment = addslashes($description);
515515

516516
// Build add index option list.
517-
$add_index_options[] = "ADD {$mysql_index_type} INDEX {$name} ({$formatted_field_options}) COMMENT '{$comment}'";
517+
if ($index_type == 'index') {
518+
$add_index_options[] = "ADD {$mysql_index_type} INDEX {$name} ({$formatted_field_options}) COMMENT '{$comment}'";
519+
}
520+
if ($index_type == 'fulltext') {
521+
$this->executeFulltextAlter($table, $name, $formatted_field_options, $comment);
522+
}
518523
}
519524

520525
return $add_index_options;
521526
}
522527

528+
/**
529+
* Execute fulltext index table alters.
530+
*
531+
* @param string $table
532+
* Table name.
533+
* @param string $name
534+
* Index name.
535+
* @param string $formatted_field_options
536+
* Fields to be indexed.
537+
* @param string $comment
538+
* Description of the index.
539+
*/
540+
protected function executeFulltextAlter(string $table, string $name, string $formatted_field_options, string $comment): void {
541+
try {
542+
// Innodb only allows adding one fulltext index at a time.
543+
$command = $this->connection->prepareStatement("ALTER TABLE {{$table}} ADD FULLTEXT INDEX {$name} ({$formatted_field_options}) COMMENT '{$comment}';", []);
544+
// Execute alter command.
545+
$command->execute();
546+
}
547+
catch (\Exception) {
548+
\Drupal::logger('Data Dictionary')->error("Error applying fulltext index to dataset {$comment}");
549+
}
550+
}
551+
523552
/**
524553
* Convert Frictionless to MySQL index types.
525554
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Drupal\Tests\datastore\Kernel\DataDictionary\AlterTableQuery;
6+
7+
use Drupal\Core\Database\Connection;
8+
use Drupal\Core\Logger\LoggerChannelFactory;
9+
use Drupal\Core\Logger\LoggerChannelInterface;
10+
use Drupal\datastore\DataDictionary\AlterTableQuery\MySQLQuery;
11+
use Drupal\KernelTests\KernelTestBase;
12+
13+
/**
14+
* @coversDefaultClass \Drupal\datastore\DataDictionary\AlterTableQuery\MySQLQuery
15+
*
16+
* @group dkan
17+
* @group datastore
18+
* @group kernel
19+
*/
20+
class MySQLQueryTest extends KernelTestBase {
21+
22+
protected static $modules = [
23+
'common',
24+
'datastore',
25+
'metastore',
26+
];
27+
28+
/**
29+
* @covers ::executeFulltextAlter
30+
*/
31+
public function testExecuteFullTextAlterWithException(): void {
32+
$exception_message = 'Test exception message.';
33+
$comment_message = 'comment message';
34+
35+
// Throw an exception from the connection object.
36+
$connection = $this->getMockBuilder(Connection::class)
37+
->disableOriginalConstructor()
38+
->onlyMethods(['prepareStatement'])
39+
->getMockForAbstractClass();
40+
$connection->expects($this->once())
41+
->method('prepareStatement')
42+
->willThrowException(new \Exception($exception_message));
43+
44+
$this->container->set('database', $connection);
45+
46+
// Set up a logger channel to expect our log message.
47+
$logger = $this->getMockBuilder(LoggerChannelInterface::class)
48+
->onlyMethods(['error'])
49+
->getMockForAbstractClass();
50+
// Error() must be called once, with our special message.
51+
$logger->expects($this->once())
52+
->method('error')
53+
->with('Error applying fulltext index to dataset ' . $comment_message);
54+
55+
// Mock a logger factory to return our special mocked logger.
56+
$logger_factory = $this->getMockBuilder(LoggerChannelFactory::class)
57+
->disableOriginalConstructor()
58+
->onlyMethods(['get'])
59+
->getMock();
60+
$logger_factory->expects($this->once())
61+
->method('get')
62+
->willReturn($logger);
63+
64+
$this->container->set('logger.factory', $logger_factory);
65+
66+
// Get a MySQLQuery object to test.
67+
$table = 'foo';
68+
$mysql_query = new MySQLQuery(
69+
$connection,
70+
$this->container->get('pdlt.converter.strptime_to_mysql'),
71+
$table,
72+
[],
73+
[]
74+
);
75+
76+
// Set executeFulltextAlter() to be public and run it.
77+
$ref_full_text_alter = new \ReflectionMethod($mysql_query, 'executeFulltextAlter');
78+
$ref_full_text_alter->setAccessible(TRUE);
79+
$ref_full_text_alter->invokeArgs($mysql_query, ['', '', '', $comment_message]);
80+
}
81+
82+
}

modules/datastore/tests/src/Unit/DataDictionary/AlterTableQuery/MySQLQueryTest.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,9 @@ public function testExecute(): void {
122122
$this->assertEquals("ALTER TABLE {" . $table . "} MODIFY COLUMN foo TEXT COMMENT 'Foo', " .
123123
"MODIFY COLUMN bar DECIMAL(10, 5) COMMENT 'Bar', " .
124124
"MODIFY COLUMN baz DATE COMMENT 'Baz', " .
125-
"ADD INDEX index1 (foo (12), bar, baz) COMMENT 'Fizz', " .
126-
"ADD FULLTEXT INDEX index2 (foo (6), baz) COMMENT '';", $query);
125+
"ADD INDEX index1 (foo (12), bar, baz) COMMENT 'Fizz';", $query);
127126
}
128127

129-
130128
/**
131129
* Ensure alter fails when attempting to apply decimal type to large numbers.
132130
*/

0 commit comments

Comments
 (0)