Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[10.x] Add support for native column modifying #45487

Merged
merged 6 commits into from
Jan 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Illuminate/Database/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ public function isDoctrineAvailable()
}

/**
* Indicates whether native alter operations will be used when dropping or renaming columns, even if Doctrine DBAL is installed.
* Indicates whether native alter operations will be used when dropping, renaming, or modifying columns, even if Doctrine DBAL is installed.
*
* @return bool
*/
Expand Down
56 changes: 11 additions & 45 deletions src/Illuminate/Database/Schema/Blueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public function build(Connection $connection, Grammar $grammar)
*/
public function toSql(Connection $connection, Grammar $grammar)
{
$this->addImpliedCommands($grammar);
$this->addImpliedCommands($connection, $grammar);

$statements = [];

Expand Down Expand Up @@ -183,10 +183,11 @@ protected function commandsNamed(array $names)
/**
* Add the commands that are implied by the blueprint's state.
*
* @param \Illuminate\Database\Connection $connection
* @param \Illuminate\Database\Schema\Grammars\Grammar $grammar
* @return void
*/
protected function addImpliedCommands(Grammar $grammar)
protected function addImpliedCommands(Connection $connection, Grammar $grammar)
{
if (count($this->getAddedColumns()) > 0 && ! $this->creating()) {
array_unshift($this->commands, $this->createCommand('add'));
Expand All @@ -198,7 +199,7 @@ protected function addImpliedCommands(Grammar $grammar)

$this->addFluentIndexes();

$this->addFluentCommands($grammar);
$this->addFluentCommands($connection, $grammar);
}

/**
Expand Down Expand Up @@ -236,24 +237,19 @@ protected function addFluentIndexes()
/**
* Add the fluent commands specified on any columns.
*
* @param \Illuminate\Database\Connection $connection
* @param \Illuminate\Database\Schema\Grammars\Grammar $grammar
* @return void
*/
public function addFluentCommands(Grammar $grammar)
public function addFluentCommands(Connection $connection, Grammar $grammar)
{
foreach ($this->columns as $column) {
foreach ($grammar->getFluentCommands() as $commandName) {
$attributeName = lcfirst($commandName);

if (! isset($column->{$attributeName})) {
taylorotwell marked this conversation as resolved.
Show resolved Hide resolved
continue;
}

$value = $column->{$attributeName};
if ($column->change && ! $connection->usingNativeSchemaOperations()) {
continue;
}

$this->addCommand(
$commandName, compact('value', 'column')
);
foreach ($grammar->getFluentCommands() as $commandName) {
$this->addCommand($commandName, compact('column'));
}
}
}
Expand Down Expand Up @@ -1786,34 +1782,4 @@ public function getChangedColumns()
return (bool) $column->change;
});
}

/**
* Determine if the blueprint has auto-increment columns.
*
* @return bool
*/
public function hasAutoIncrementColumn()
{
return ! is_null(collect($this->getAddedColumns())->first(function ($column) {
return $column->autoIncrement === true;
}));
}

/**
* Get the auto-increment column starting values.
*
* @return array
*/
public function autoIncrementingStartingValues()
{
if (! $this->hasAutoIncrementColumn()) {
return [];
}

return collect($this->getAddedColumns())->mapWithKeys(function ($column) {
return $column->autoIncrement === true
? [$column->name => $column->get('startingValue', $column->get('from'))]
: [$column->name => null];
})->filter()->all();
}
}
4 changes: 2 additions & 2 deletions src/Illuminate/Database/Schema/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Builder
public static $defaultMorphKeyType = 'int';

/**
* Indicates whether Doctrine DBAL usage will be prevented if possible when dropping and renaming columns.
* Indicates whether Doctrine DBAL usage will be prevented if possible when dropping, renaming, and modifying columns.
*
* @var bool
*/
Expand Down Expand Up @@ -113,7 +113,7 @@ public static function morphUsingUlids()
}

/**
* Attempt to use native schema operations for dropping and renaming columns, even if Doctrine DBAL is installed.
* Attempt to use native schema operations for dropping, renaming, and modifying columns, even if Doctrine DBAL is installed.
*
* @param bool $value
* @return void
Expand Down
6 changes: 3 additions & 3 deletions src/Illuminate/Database/Schema/Grammars/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @param \Illuminate\Database\Connection $connection
* @return array
* @return array|string
*
* @throws \RuntimeException
*/
Expand Down Expand Up @@ -162,7 +162,7 @@ public function compileForeign(Blueprint $blueprint, Fluent $command)
}

/**
* Compile the blueprint's column definitions.
* Compile the blueprint's added column definitions.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @return array
Expand Down Expand Up @@ -286,7 +286,7 @@ public function wrapTable($table)
/**
* Wrap a value in keyword identifiers.
*
* @param \Illuminate\Database\Query\Expression|string $value
* @param \Illuminate\Support\Fluent|\Illuminate\Database\Query\Expression|string $value
* @param bool $prefixAlias
* @return string
*/
Expand Down
113 changes: 86 additions & 27 deletions src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Illuminate\Database\Schema\Grammars;

use Illuminate\Database\Connection;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Fluent;
use RuntimeException;
Expand All @@ -15,8 +16,8 @@ class MySqlGrammar extends Grammar
* @var string[]
*/
protected $modifiers = [
'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable', 'Invisible',
'Srid', 'Default', 'Increment', 'Comment', 'After', 'First',
'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable',
'Srid', 'Default', 'OnUpdate', 'Invisible', 'Increment', 'Comment', 'After', 'First',
];

/**
Expand All @@ -26,6 +27,13 @@ class MySqlGrammar extends Grammar
*/
protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger'];

/**
* The commands to be executed outside of create or alter command.
*
* @var string[]
*/
protected $fluentCommands = ['AutoIncrementStartingValues'];

/**
* Compile a create database command.
*
Expand Down Expand Up @@ -83,7 +91,7 @@ public function compileColumnListing()
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @param \Illuminate\Database\Connection $connection
* @return array
* @return string
*/
public function compileCreate(Blueprint $blueprint, Fluent $command, Connection $connection)
{
Expand All @@ -101,9 +109,7 @@ public function compileCreate(Blueprint $blueprint, Fluent $command, Connection
// Finally, we will append the engine configuration onto this SQL statement as
// the final thing we do before returning this finished SQL. Once this gets
// added the query will be ready to execute against the real connections.
return array_values(array_filter(array_merge([$this->compileCreateEngine(
$sql, $connection, $blueprint
)], $this->compileAutoIncrementStartingValues($blueprint))));
return $this->compileCreateEngine($sql, $connection, $blueprint);
}

/**
Expand All @@ -112,15 +118,15 @@ public function compileCreate(Blueprint $blueprint, Fluent $command, Connection
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @param \Illuminate\Database\Connection $connection
* @return array
* @return string
*/
protected function compileCreateTable($blueprint, $command, $connection)
{
return trim(sprintf('%s table %s (%s)',
return sprintf('%s table %s (%s)',
$blueprint->temporary ? 'create temporary' : 'create',
$this->wrapTable($blueprint),
implode(', ', $this->getColumns($blueprint))
));
);
}

/**
Expand Down Expand Up @@ -178,29 +184,28 @@ protected function compileCreateEngine($sql, Connection $connection, Blueprint $
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return array
* @return string
*/
public function compileAdd(Blueprint $blueprint, Fluent $command)
{
$columns = $this->prefixArray('add', $this->getColumns($blueprint));

return array_values(array_merge(
['alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns)],
$this->compileAutoIncrementStartingValues($blueprint)
));
return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns);
}

/**
* Compile the auto-incrementing column starting values.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @return array
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileAutoIncrementStartingValues(Blueprint $blueprint)
public function compileAutoIncrementStartingValues(Blueprint $blueprint, Fluent $command)
{
return collect($blueprint->autoIncrementingStartingValues())->map(function ($value, $column) use ($blueprint) {
return 'alter table '.$this->wrapTable($blueprint->getTable()).' auto_increment = '.$value;
})->all();
if ($command->column->autoIncrement
&& $value = $command->column->get('startingValue', $command->column->get('from'))) {
return 'alter table '.$this->wrapTable($blueprint).' auto_increment = '.$value;
}
}

/**
Expand All @@ -222,6 +227,38 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne
: parent::compileRenameColumn($blueprint, $command, $connection);
}

/**
* Compile a change column command into a series of SQL statements.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @param \Illuminate\Database\Connection $connection
* @return array|string
*
* @throws \RuntimeException
*/
public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection)
{
if (! $connection->usingNativeSchemaOperations()) {
return parent::compileChange($blueprint, $command, $connection);
}

$columns = [];

foreach ($blueprint->getChangedColumns() as $column) {
$sql = sprintf('%s %s%s %s',
is_null($column->renameTo) ? 'modify' : 'change',
$this->wrap($column),
is_null($column->renameTo) ? '' : ' '.$this->wrap($column->renameTo),
$this->getType($column)
);

$columns[] = $this->addModifiers($sql, $blueprint, $column);
}

return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns);
}

/**
* Compile a primary key command.
*
Expand Down Expand Up @@ -758,13 +795,17 @@ protected function typeDate(Fluent $column)
*/
protected function typeDateTime(Fluent $column)
{
$columnType = $column->precision ? "datetime($column->precision)" : 'datetime';

$current = $column->precision ? "CURRENT_TIMESTAMP($column->precision)" : 'CURRENT_TIMESTAMP';

$columnType = $column->useCurrent ? "$columnType default $current" : $columnType;
if ($column->useCurrent) {
$column->default(new Expression($current));
}

if ($column->useCurrentOnUpdate) {
$column->onUpdate(new Expression($current));
}

return $column->useCurrentOnUpdate ? "$columnType on update $current" : $columnType;
return $column->precision ? "datetime($column->precision)" : 'datetime';
}

/**
Expand Down Expand Up @@ -808,13 +849,17 @@ protected function typeTimeTz(Fluent $column)
*/
protected function typeTimestamp(Fluent $column)
{
$columnType = $column->precision ? "timestamp($column->precision)" : 'timestamp';

$current = $column->precision ? "CURRENT_TIMESTAMP($column->precision)" : 'CURRENT_TIMESTAMP';

$columnType = $column->useCurrent ? "$columnType default $current" : $columnType;
if ($column->useCurrent) {
$column->default(new Expression($current));
}

return $column->useCurrentOnUpdate ? "$columnType on update $current" : $columnType;
if ($column->useCurrentOnUpdate) {
$column->onUpdate(new Expression($current));
}

return $column->precision ? "timestamp($column->precision)" : 'timestamp';
}

/**
Expand Down Expand Up @@ -1119,6 +1164,20 @@ protected function modifyDefault(Blueprint $blueprint, Fluent $column)
}
}

/**
* Get the SQL for an "on update" column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyOnUpdate(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->onUpdate)) {
return ' on update '.$column->onUpdate;
}
}

/**
* Get the SQL for an auto-increment column modifier.
*
Expand Down