Skip to content

Commit

Permalink
Improve MySQL connect init time by setting all our variables in a sin…
Browse files Browse the repository at this point in the history
…gle shot
  • Loading branch information
GrahamCampbell committed Feb 19, 2024
1 parent 7a32ff0 commit 9943279
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 102 deletions.
21 changes: 17 additions & 4 deletions src/Illuminate/Database/Connectors/MariaDbConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,28 @@

class MariaDbConnector extends MySqlConnector implements ConnectorInterface
{

/**
* Get the query to enable strict mode.
* Get the sql_mode value.
*
* @param \PDO $connection
* @param array $config
* @return string
* @return string|null
*/
protected function strictMode(PDO $connection, $config)
protected function getSqlMode($connection, $config)
{
return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'";
if (isset($config['modes'])) {
return implode(',', $config['modes']);
}

if (! isset($config['strict'])) {
return null;
}

if (! $config['strict']) {
return 'NO_ENGINE_SUBSTITUTION';
}

return 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
}
}
130 changes: 41 additions & 89 deletions src/Illuminate/Database/Connectors/MySqlConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,78 +27,52 @@ public function connect(array $config)
$connection->exec("use `{$config['database']}`;");
}

$this->configureIsolationLevel($connection, $config);

$this->configureEncoding($connection, $config);

// Next, we will check to see if a timezone has been specified in this config
// and if it has we will issue a statement to modify the timezone with the
// database. Setting this DB timezone is an optional configuration item.
$this->configureTimezone($connection, $config);

$this->setModes($connection, $config);
$this->configureConnection($connection, $config);

return $connection;
}

/**
* Set the connection transaction isolation level.
* Configure the connection.
*
* @param \PDO $connection
* @param array $config
* @return void
*/
protected function configureIsolationLevel($connection, array $config)
protected function configureConnection($connection, array $config)
{
if (! isset($config['isolation_level'])) {
return;
}
$statements = [];

$connection->prepare(
"SET SESSION TRANSACTION ISOLATION LEVEL {$config['isolation_level']}"
)->execute();
}
// First, we set the transaction isolation level.
if (isset($config['isolation_level'])) {
$statements[] = sprintf('SESSION TRANSACTION ISOLATION LEVEL %s', $config['isolation_level']);
}

/**
* Set the connection character set and collation.
*
* @param \PDO $connection
* @param array $config
* @return void|\PDO
*/
protected function configureEncoding($connection, array $config)
{
if (! isset($config['charset'])) {
return $connection;
// Now, we set the charset and possibly the collation.
if (isset($config['charset'])) {
if (isset($config['collation'])) {
$statements[] = sprintf("NAMES '%s' COLLATE '%s'", $config['charset'], $config['collation']);
} else {
$statements[] = sprintf("NAMES '%s'", $config['charset']);
}
}

$connection->prepare(
"set names '{$config['charset']}'".$this->getCollation($config)
)->execute();
}
// Next, we will check to see if a timezone has been specified in this config
// and if it has we will issue a statement to modify the timezone with the
// database. Setting this DB timezone is an optional configuration item.
if (isset($config['timezone'])) {
$statements[] = sprintf("time_zone='%s'", $config['timezone']);
}

/**
* Get the collation for the configuration.
*
* @param array $config
* @return string
*/
protected function getCollation(array $config)
{
return isset($config['collation']) ? " collate '{$config['collation']}'" : '';
}
// Next, we set the correct sql_mode mode according to the config.
$sqlMode = $this->getSqlMode($connection, $config);
if (null !== $sqlMode) {
$statements[] = sprintf("SESSION sql_mode='%s'", $sqlMode);
}

/**
* Set the timezone on the connection.
*
* @param \PDO $connection
* @param array $config
* @return void
*/
protected function configureTimezone($connection, array $config)
{
if (isset($config['timezone'])) {
$connection->prepare('set time_zone="'.$config['timezone'].'"')->execute();
// Finally, execute a single SET command with all our statements.
if ([] !== $statements) {
$connection->exec(sprintf('SET %s;', implode(', ', $statements)));
}
}

Expand Down Expand Up @@ -155,54 +129,32 @@ protected function getHostDsn(array $config)
}

/**
* Set the modes for the connection.
* Get the sql_mode value.
*
* @param \PDO $connection
* @param array $config
* @return void
* @return string|null
*/
protected function setModes(PDO $connection, array $config)
protected function getSqlMode($connection, $config)
{
if (isset($config['modes'])) {
$this->setCustomModes($connection, $config);
} elseif (isset($config['strict'])) {
if ($config['strict']) {
$connection->prepare($this->strictMode($connection, $config))->execute();
} else {
$connection->prepare("set session sql_mode='NO_ENGINE_SUBSTITUTION'")->execute();
}
return implode(',', $config['modes']);
}
}

/**
* Set the custom modes on the connection.
*
* @param \PDO $connection
* @param array $config
* @return void
*/
protected function setCustomModes(PDO $connection, array $config)
{
$modes = implode(',', $config['modes']);
if (! isset($config['strict'])) {
return null;
}

$connection->prepare("set session sql_mode='{$modes}'")->execute();
}
if (! $config['strict']) {
return 'NO_ENGINE_SUBSTITUTION';
}

/**
* Get the query to enable strict mode.
*
* @param \PDO $connection
* @param array $config
* @return string
*/
protected function strictMode(PDO $connection, $config)
{
$version = $config['version'] ?? $connection->getAttribute(PDO::ATTR_SERVER_VERSION);

if (version_compare($version, '8.0.11') >= 0) {
return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'";
return 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
}

return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'";
return 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
}
}
13 changes: 4 additions & 9 deletions tests/Database/DatabaseConnectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,8 @@ public function testMySqlConnectCallsCreateConnectionWithProperArguments($dsn, $
$connection = m::mock(PDO::class);
$connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']);
$connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->willReturn($connection);
$statement = m::mock(PDOStatement::class);
$connection->shouldReceive('prepare')->once()->with('set names \'utf8\' collate \'utf8_unicode_ci\'')->andReturn($statement);
$statement->shouldReceive('execute')->once();
$connection->shouldReceive('exec')->zeroOrMoreTimes();
$connection->shouldReceive('exec')->once()->with('use `bar`;')->andReturn(true);
$connection->shouldReceive('exec')->once()->with("SET NAMES 'utf8' COLLATE 'utf8_unicode_ci';")->andReturn(true);
$result = $connector->connect($config);

$this->assertSame($result, $connection);
Expand All @@ -63,11 +61,8 @@ public function testMySqlConnectCallsCreateConnectionWithIsolationLevel()
$connection = m::mock(PDO::class);
$connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']);
$connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->willReturn($connection);
$statement = m::mock(PDOStatement::class);
$connection->shouldReceive('prepare')->once()->with('set names \'utf8\' collate \'utf8_unicode_ci\'')->andReturn($statement);
$connection->shouldReceive('prepare')->once()->with('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ')->andReturn($statement);
$statement->shouldReceive('execute')->zeroOrMoreTimes();
$connection->shouldReceive('exec')->zeroOrMoreTimes();
$connection->shouldReceive('exec')->once()->with('use `bar`;')->andReturn(true);
$connection->shouldReceive('exec')->once()->with("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ, NAMES 'utf8' COLLATE 'utf8_unicode_ci';")->andReturn(true);
$result = $connector->connect($config);

$this->assertSame($result, $connection);
Expand Down

0 comments on commit 9943279

Please sign in to comment.