From c6560885f26b0ef34b557128374bc7074c9b704f Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 13 Dec 2022 02:16:32 +0330 Subject: [PATCH 01/19] add support for native column modifying on MySQL --- .../Database/Schema/Grammars/Grammar.php | 26 +++++++++++++++++-- .../Database/Schema/Grammars/MySqlGrammar.php | 18 +++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/Grammar.php b/src/Illuminate/Database/Schema/Grammars/Grammar.php index ea8333e40436..9d15bfbaad8c 100755 --- a/src/Illuminate/Database/Schema/Grammars/Grammar.php +++ b/src/Illuminate/Database/Schema/Grammars/Grammar.php @@ -77,7 +77,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 */ @@ -155,7 +155,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 @@ -176,6 +176,28 @@ protected function getColumns(Blueprint $blueprint) return $columns; } + /** + * Compile the blueprint's changed column definitions. + * + * @param \Illuminate\Database\Schema\Blueprint $blueprint + * @return array + */ + protected function getChangedColumns(Blueprint $blueprint) + { + $columns = []; + + foreach ($blueprint->getChangedColumns() as $column) { + // Each of the column types has their own compiler functions, which are tasked + // with turning the column definition into its SQL format for this platform + // used by the connection. The column's modifiers are compiled and added. + $sql = $this->wrap($column).' '.$this->getType($column); + + $columns[] = $this->addModifiers($sql, $blueprint, $column); + } + + return $columns; + } + /** * Get the SQL for the column data type. * diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 40ee3c8b873d..25b98b934295 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -222,6 +222,24 @@ 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) + { + return $connection->usingNativeSchemaOperations() + ? 'alter table '.$this->wrapTable($blueprint).' ' + .implode(', ', $this->prefixArray('modify', $this->getColumns($blueprint))) + : parent::compileChange($blueprint, $command, $connection); + } + /** * Compile a primary key command. * From ee221d2b9eac66a43f72bdbff3f856e30dbb316b Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 13 Dec 2022 19:10:25 +0330 Subject: [PATCH 02/19] add support for native column modifying on PostgreSQL fix a typo on MySQL grammar --- .../Database/Schema/Grammars/MySqlGrammar.php | 2 +- .../Schema/Grammars/PostgresGrammar.php | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 25b98b934295..06ef5f0062f5 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -236,7 +236,7 @@ public function compileChange(Blueprint $blueprint, Fluent $command, Connection { return $connection->usingNativeSchemaOperations() ? 'alter table '.$this->wrapTable($blueprint).' ' - .implode(', ', $this->prefixArray('modify', $this->getColumns($blueprint))) + .implode(', ', $this->prefixArray('modify', $this->getChangedColumns($blueprint))) : parent::compileChange($blueprint, $command, $connection); } diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index ef60d0ff820f..3631adb5f319 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -149,6 +149,26 @@ 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) + { + return $connection->usingNativeSchemaOperations() + ? sprintf('alter table %s %s', + $this->wrapTable($blueprint), + implode(', ', $this->prefixArray('alter column', $this->getChangedColumns($blueprint))) + ) + : parent::compileChange($blueprint, $command, $connection); + } + /** * Compile a primary key command. * @@ -1138,4 +1158,26 @@ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) return " generated always as ({$column->storedAs}) stored"; } } + + /** + * Compile the blueprint's changed column definitions. + * + * @param \Illuminate\Database\Schema\Blueprint $blueprint + * @return array + */ + protected function getChangedColumns(Blueprint $blueprint) + { + $columns = []; + + foreach ($blueprint->getChangedColumns() as $column) { + // Each of the column types has their own compiler functions, which are tasked + // with turning the column definition into its SQL format for this platform + // used by the connection. The column's modifiers are compiled and added. + $sql = $this->wrap($column).' type '.$this->getType($column); + + $columns[] = $this->addModifiers($sql, $blueprint, $column); + } + + return $columns; + } } From 137be150f5980f87a61a77930b896547092375bc Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 13 Dec 2022 21:35:06 +0330 Subject: [PATCH 03/19] set auto increment starting value --- src/Illuminate/Database/Schema/Blueprint.php | 8 ++++++-- src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php | 9 +++------ .../Database/Schema/Grammars/PostgresGrammar.php | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index ee0988d5273a..965033b4f7da 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -188,6 +188,10 @@ protected function commandsNamed(array $names) */ protected function addImpliedCommands(Grammar $grammar) { + if ($this->hasAutoIncrementColumn() && ! $this->creating()) { + array_unshift($this->commands, $this->createCommand('autoIncrementStartingValues')); + } + if (count($this->getAddedColumns()) > 0 && ! $this->creating()) { array_unshift($this->commands, $this->createCommand('add')); } @@ -1794,7 +1798,7 @@ public function getChangedColumns() */ public function hasAutoIncrementColumn() { - return ! is_null(collect($this->getAddedColumns())->first(function ($column) { + return ! is_null(collect($this->columns)->first(function ($column) { return $column->autoIncrement === true; })); } @@ -1810,7 +1814,7 @@ public function autoIncrementingStartingValues() return []; } - return collect($this->getAddedColumns())->mapWithKeys(function ($column) { + return collect($this->columns)->mapWithKeys(function ($column) { return $column->autoIncrement === true ? [$column->name => $column->get('startingValue', $column->get('from'))] : [$column->name => null]; diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 06ef5f0062f5..0d2120e948da 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -178,16 +178,13 @@ 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); } /** @@ -200,7 +197,7 @@ public function compileAutoIncrementStartingValues(Blueprint $blueprint) { return collect($blueprint->autoIncrementingStartingValues())->map(function ($value, $column) use ($blueprint) { return 'alter table '.$this->wrapTable($blueprint->getTable()).' auto_increment = '.$value; - })->all(); + })->values()->all(); } /** diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 3631adb5f319..237ea44712c4 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -111,10 +111,10 @@ public function compileCreate(Blueprint $blueprint, Fluent $command) */ public function compileAdd(Blueprint $blueprint, Fluent $command) { - return array_values(array_filter(array_merge([sprintf('alter table %s %s', + return sprintf('alter table %s %s', $this->wrapTable($blueprint), implode(', ', $this->prefixArray('add column', $this->getColumns($blueprint))) - )], $this->compileAutoIncrementStartingValues($blueprint)))); + ); } /** @@ -127,7 +127,7 @@ public function compileAutoIncrementStartingValues(Blueprint $blueprint) { return collect($blueprint->autoIncrementingStartingValues())->map(function ($value, $column) use ($blueprint) { return 'alter sequence '.$blueprint->getTable().'_'.$column.'_seq restart with '.$value; - })->all(); + })->values()->all(); } /** From 09afcd25803b79f7582c6deb95cc11ebc4465632 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Wed, 14 Dec 2022 21:00:27 +0330 Subject: [PATCH 04/19] support removing comment on PostgreSQL --- src/Illuminate/Database/Schema/Blueprint.php | 2 +- src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 965033b4f7da..9d600db0457a 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -249,7 +249,7 @@ public function addFluentCommands(Grammar $grammar) foreach ($grammar->getFluentCommands() as $commandName) { $attributeName = lcfirst($commandName); - if (! isset($column->{$attributeName})) { + if (! array_key_exists($attributeName, $column->getAttributes())) { continue; } diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 237ea44712c4..53ad083cea3f 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -532,7 +532,7 @@ public function compileComment(Blueprint $blueprint, Fluent $command) return sprintf('comment on column %s.%s is %s', $this->wrapTable($blueprint), $this->wrap($command->column->name), - "'".str_replace("'", "''", $command->value)."'" + is_null($command->value) ? 'NULL' : "'".str_replace("'", "''", $command->value)."'" ); } @@ -547,7 +547,7 @@ public function compileTableComment(Blueprint $blueprint, Fluent $command) { return sprintf('comment on table %s is %s', $this->wrapTable($blueprint), - "'".str_replace("'", "''", $command->comment)."'" + is_null($command->value) ? 'NULL' : "'".str_replace("'", "''", $command->comment)."'" ); } From 6c6634a7aa22ed1e30004a3f1eebfacd3dfd1eac Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Wed, 14 Dec 2022 21:06:16 +0330 Subject: [PATCH 05/19] fix a typo --- src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 53ad083cea3f..5467addb8bf0 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -547,7 +547,7 @@ public function compileTableComment(Blueprint $blueprint, Fluent $command) { return sprintf('comment on table %s is %s', $this->wrapTable($blueprint), - is_null($command->value) ? 'NULL' : "'".str_replace("'", "''", $command->comment)."'" + is_null($command->comment) ? 'NULL' : "'".str_replace("'", "''", $command->comment)."'" ); } From 96a38e9dfac074a641c0d31bbdb3ca73eeacc792 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Thu, 15 Dec 2022 20:13:53 +0330 Subject: [PATCH 06/19] add generatedAs to list of modifiers --- .../Schema/Grammars/PostgresGrammar.php | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 5467addb8bf0..d4421f7fffd1 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -20,7 +20,7 @@ class PostgresGrammar extends Grammar * * @var string[] */ - protected $modifiers = ['Collate', 'Increment', 'Nullable', 'Default', 'VirtualAs', 'StoredAs']; + protected $modifiers = ['GeneratedAs', 'Collate', 'Increment', 'Nullable', 'Default', 'VirtualAs', 'StoredAs']; /** * The columns available as serials. @@ -716,18 +716,7 @@ protected function generatableColumn($type, Fluent $column) ])[$type]; } - $options = ''; - - if (! is_bool($column->generatedAs) && ! empty($column->generatedAs)) { - $options = sprintf(' (%s)', $column->generatedAs); - } - - return sprintf( - '%s generated %s as identity%s', - $type, - $column->always ? 'always' : 'by default', - $options - ); + return $type; } /** @@ -1159,6 +1148,30 @@ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) } } + /** + * Get the SQL for a generated column modifier. + * + * @param \Illuminate\Database\Schema\Blueprint $blueprint + * @param \Illuminate\Support\Fluent $column + * @return string|null + */ + protected function modifyGeneratedAs(Blueprint $blueprint, Fluent $column) + { + if ($column->generatedAs !== null) { + $options = ''; + + if (! is_bool($column->generatedAs) && ! empty($column->generatedAs)) { + $options = sprintf(' (%s)', $column->generatedAs); + } + + return sprintf( + ' generated %s as identity%s', + $column->always ? 'always' : 'by default', + $options + ); + } + } + /** * Compile the blueprint's changed column definitions. * From e53fcfe5aff4cb79854503b9190ac7c068d6f673 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Sat, 17 Dec 2022 18:18:33 +0330 Subject: [PATCH 07/19] fix MySQL and PostgreSQL alter syntax --- src/Illuminate/Database/Schema/Blueprint.php | 2 +- .../Database/Schema/Grammars/Grammar.php | 22 --- .../Database/Schema/Grammars/MySqlGrammar.php | 21 ++- .../Schema/Grammars/PostgresGrammar.php | 133 ++++++++++-------- .../DatabasePostgresSchemaGrammarTest.php | 8 +- 5 files changed, 96 insertions(+), 90 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 9d600db0457a..b87f517989f6 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -249,7 +249,7 @@ public function addFluentCommands(Grammar $grammar) foreach ($grammar->getFluentCommands() as $commandName) { $attributeName = lcfirst($commandName); - if (! array_key_exists($attributeName, $column->getAttributes())) { + if (! $column->change && ! array_key_exists($attributeName, $column->getAttributes()) ) { continue; } diff --git a/src/Illuminate/Database/Schema/Grammars/Grammar.php b/src/Illuminate/Database/Schema/Grammars/Grammar.php index 9d15bfbaad8c..1fc44af94c86 100755 --- a/src/Illuminate/Database/Schema/Grammars/Grammar.php +++ b/src/Illuminate/Database/Schema/Grammars/Grammar.php @@ -176,28 +176,6 @@ protected function getColumns(Blueprint $blueprint) return $columns; } - /** - * Compile the blueprint's changed column definitions. - * - * @param \Illuminate\Database\Schema\Blueprint $blueprint - * @return array - */ - protected function getChangedColumns(Blueprint $blueprint) - { - $columns = []; - - foreach ($blueprint->getChangedColumns() as $column) { - // Each of the column types has their own compiler functions, which are tasked - // with turning the column definition into its SQL format for this platform - // used by the connection. The column's modifiers are compiled and added. - $sql = $this->wrap($column).' '.$this->getType($column); - - $columns[] = $this->addModifiers($sql, $blueprint, $column); - } - - return $columns; - } - /** * Get the SQL for the column data type. * diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 0d2120e948da..5c25f7ec2fbf 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -231,10 +231,23 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne */ public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) { - return $connection->usingNativeSchemaOperations() - ? 'alter table '.$this->wrapTable($blueprint).' ' - .implode(', ', $this->prefixArray('modify', $this->getChangedColumns($blueprint))) - : parent::compileChange($blueprint, $command, $connection); + if ($connection->usingNativeSchemaOperations()) { + $columns = []; + + foreach ($blueprint->getChangedColumns() as $column) { + // Each of the column types has their own compiler functions, which are tasked + // with turning the column definition into its SQL format for this platform + // used by the connection. The column's modifiers are compiled and added. + $sql = $this->wrap($column).' '.$this->getType($column); + + $columns[] = $this->addModifiers($sql, $blueprint, $column); + } + + return 'alter table '.$this->wrapTable($blueprint).' ' + .implode(', ', $this->prefixArray('modify', $columns)); + } + + return parent::compileChange($blueprint, $command, $connection); } /** diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index d4421f7fffd1..f370528cb59b 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -5,6 +5,7 @@ use Illuminate\Database\Connection; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Fluent; +use LogicException; class PostgresGrammar extends Grammar { @@ -20,7 +21,7 @@ class PostgresGrammar extends Grammar * * @var string[] */ - protected $modifiers = ['GeneratedAs', 'Collate', 'Increment', 'Nullable', 'Default', 'VirtualAs', 'StoredAs']; + protected $modifiers = ['Collate', 'Increment', 'Nullable', 'Default', 'VirtualAs', 'StoredAs', 'GeneratedAs']; /** * The columns available as serials. @@ -161,12 +162,34 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne */ public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) { - return $connection->usingNativeSchemaOperations() - ? sprintf('alter table %s %s', - $this->wrapTable($blueprint), - implode(', ', $this->prefixArray('alter column', $this->getChangedColumns($blueprint))) - ) - : parent::compileChange($blueprint, $command, $connection); + if ($connection->usingNativeSchemaOperations()) { + $changes = []; + + foreach ($blueprint->getChangedColumns() as $column) { + $sql = 'alter table '.$this->wrapTable($blueprint).' alter column '.$this->wrap($column); + + $changes[] = $sql.' type '.$this->getType($column).$this->modifyCollate($blueprint, $column); + + foreach ($this->modifiers as $modifier) { + if (in_array($modifier, ['Collate', 'Increment'])) { + // Already handled + continue; + } + + if (method_exists($this, $method = "modify{$modifier}")) { + $constraints = (array) $this->{$method}($blueprint, $column); + + foreach ($constraints as $constraint) { + $changes[] = $sql.' '.$constraint; + } + } + } + } + + return $changes; + } + + return parent::compileChange($blueprint, $command, $connection); } /** @@ -648,7 +671,7 @@ protected function typeLongText(Fluent $column) */ protected function typeInteger(Fluent $column) { - return $this->generatableColumn('integer', $column); + return $column->autoIncrement && is_null($column->generatedAs) ? 'serial' : 'integer'; } /** @@ -659,7 +682,7 @@ protected function typeInteger(Fluent $column) */ protected function typeBigInteger(Fluent $column) { - return $this->generatableColumn('bigint', $column); + return $column->autoIncrement && is_null($column->generatedAs) ? 'bigserial' : 'bigint'; } /** @@ -670,7 +693,7 @@ protected function typeBigInteger(Fluent $column) */ protected function typeMediumInteger(Fluent $column) { - return $this->generatableColumn('integer', $column); + return $this->typeInteger($column); } /** @@ -681,7 +704,7 @@ protected function typeMediumInteger(Fluent $column) */ protected function typeTinyInteger(Fluent $column) { - return $this->generatableColumn('smallint', $column); + return $this->typeSmallInteger($column); } /** @@ -692,31 +715,7 @@ protected function typeTinyInteger(Fluent $column) */ protected function typeSmallInteger(Fluent $column) { - return $this->generatableColumn('smallint', $column); - } - - /** - * Create the column definition for a generatable column. - * - * @param string $type - * @param \Illuminate\Support\Fluent $column - * @return string - */ - protected function generatableColumn($type, Fluent $column) - { - if (! $column->autoIncrement && is_null($column->generatedAs)) { - return $type; - } - - if ($column->autoIncrement && is_null($column->generatedAs)) { - return with([ - 'integer' => 'serial', - 'bigint' => 'bigserial', - 'smallint' => 'smallserial', - ])[$type]; - } - - return $type; + return $column->autoIncrement && is_null($column->generatedAs) ? 'smallserial' : 'smallint'; } /** @@ -1089,6 +1088,10 @@ protected function modifyCollate(Blueprint $blueprint, Fluent $column) */ protected function modifyNullable(Blueprint $blueprint, Fluent $column) { + if ($column->change) { + return $column->nullable ? 'drop not null' : 'set not null'; + } + return $column->nullable ? ' null' : ' not null'; } @@ -1101,6 +1104,10 @@ protected function modifyNullable(Blueprint $blueprint, Fluent $column) */ protected function modifyDefault(Blueprint $blueprint, Fluent $column) { + if ($column->change) { + return is_null($column->default) ? 'drop default' : 'set default '.$this->getDefaultValue($column->default); + } + if (! is_null($column->default)) { return ' default '.$this->getDefaultValue($column->default); } @@ -1129,7 +1136,15 @@ protected function modifyIncrement(Blueprint $blueprint, Fluent $column) */ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) { - if ($column->virtualAs !== null) { + if ($column->change) { + if (array_key_exists('virtualAs', $column->getAttributes()) && is_null($column->virtualAs)) { + return 'drop expression if exists'; + } + + throw new LogicException('This database driver does not support modifying generated columns.'); + } + + if (! is_null($column->virtualAs)) { return " generated always as ({$column->virtualAs})"; } } @@ -1143,54 +1158,54 @@ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) */ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) { - if ($column->storedAs !== null) { + if ($column->change) { + if (array_key_exists('storedAs', $column->getAttributes()) && is_null($column->storedAs)) { + return 'drop expression if exists'; + } + + throw new LogicException('This database driver does not support modifying generated columns.'); + } + + if (! is_null($column->storedAs)) { return " generated always as ({$column->storedAs}) stored"; } } /** - * Get the SQL for a generated column modifier. + * Get the SQL for an identity column modifier. * * @param \Illuminate\Database\Schema\Blueprint $blueprint * @param \Illuminate\Support\Fluent $column - * @return string|null + * @return string|array|null */ protected function modifyGeneratedAs(Blueprint $blueprint, Fluent $column) { - if ($column->generatedAs !== null) { + $sql = null; + + if (! is_null($column->generatedAs)) { $options = ''; if (! is_bool($column->generatedAs) && ! empty($column->generatedAs)) { $options = sprintf(' (%s)', $column->generatedAs); } - return sprintf( + $sql = sprintf( ' generated %s as identity%s', $column->always ? 'always' : 'by default', $options ); } - } - /** - * Compile the blueprint's changed column definitions. - * - * @param \Illuminate\Database\Schema\Blueprint $blueprint - * @return array - */ - protected function getChangedColumns(Blueprint $blueprint) - { - $columns = []; + if ($column->change) { + $changes = ['drop identity if exists']; - foreach ($blueprint->getChangedColumns() as $column) { - // Each of the column types has their own compiler functions, which are tasked - // with turning the column definition into its SQL format for this platform - // used by the connection. The column's modifiers are compiled and added. - $sql = $this->wrap($column).' type '.$this->getType($column); + if (! is_null($sql)) { + $changes[] = 'add '.$sql; + } - $columns[] = $this->addModifiers($sql, $blueprint, $column); + return $changes; } - return $columns; + return $sql; } } diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 98066f4f90eb..aee18467e888 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -902,25 +902,25 @@ public function testAddingGeneratedAs() $blueprint->increments('foo')->generatedAs(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "foo" integer generated by default as identity primary key not null', $statements[0]); + $this->assertSame('alter table "users" add column "foo" integer primary key not null generated by default as identity', $statements[0]); // With always modifier $blueprint = new Blueprint('users'); $blueprint->increments('foo')->generatedAs()->always(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "foo" integer generated always as identity primary key not null', $statements[0]); + $this->assertSame('alter table "users" add column "foo" integer primary key not null generated always as identity', $statements[0]); // With sequence options $blueprint = new Blueprint('users'); $blueprint->increments('foo')->generatedAs('increment by 10 start with 100'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "foo" integer generated by default as identity (increment by 10 start with 100) primary key not null', $statements[0]); + $this->assertSame('alter table "users" add column "foo" integer primary key not null generated by default as identity (increment by 10 start with 100)', $statements[0]); // Not a primary key $blueprint = new Blueprint('users'); $blueprint->integer('foo')->generatedAs(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table "users" add column "foo" integer generated by default as identity not null', $statements[0]); + $this->assertSame('alter table "users" add column "foo" integer not null generated by default as identity', $statements[0]); } public function testAddingVirtualAs() From d0674750f63d42d77ec744223f2ad8ced0df8f2d Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Sat, 17 Dec 2022 18:55:58 +0330 Subject: [PATCH 08/19] fix tests --- src/Illuminate/Database/Schema/Blueprint.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index b87f517989f6..7d4844284f1b 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -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 = []; @@ -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 ($this->hasAutoIncrementColumn() && ! $this->creating()) { array_unshift($this->commands, $this->createCommand('autoIncrementStartingValues')); @@ -202,7 +203,7 @@ protected function addImpliedCommands(Grammar $grammar) $this->addFluentIndexes(); - $this->addFluentCommands($grammar); + $this->addFluentCommands($connection, $grammar); } /** @@ -240,16 +241,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 (! $column->change && ! array_key_exists($attributeName, $column->getAttributes()) ) { + if (! array_key_exists($attributeName, $column->getAttributes()) + && ! $column->change + && ! $connection->usingNativeSchemaOperations()) { continue; } From 513859c6d967d5758d9a82095e1ec2c0bd3bb918 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Sat, 17 Dec 2022 19:52:06 +0330 Subject: [PATCH 09/19] revert changes of the last commit --- src/Illuminate/Database/Schema/Blueprint.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 7d4844284f1b..85db3212d2e6 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -119,7 +119,7 @@ public function build(Connection $connection, Grammar $grammar) */ public function toSql(Connection $connection, Grammar $grammar) { - $this->addImpliedCommands($connection, $grammar); + $this->addImpliedCommands($grammar); $statements = []; @@ -183,11 +183,10 @@ 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(Connection $connection, Grammar $grammar) + protected function addImpliedCommands(Grammar $grammar) { if ($this->hasAutoIncrementColumn() && ! $this->creating()) { array_unshift($this->commands, $this->createCommand('autoIncrementStartingValues')); @@ -203,7 +202,7 @@ protected function addImpliedCommands(Connection $connection, Grammar $grammar) $this->addFluentIndexes(); - $this->addFluentCommands($connection, $grammar); + $this->addFluentCommands($grammar); } /** @@ -241,19 +240,16 @@ 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(Connection $connection, Grammar $grammar) + public function addFluentCommands(Grammar $grammar) { foreach ($this->columns as $column) { foreach ($grammar->getFluentCommands() as $commandName) { $attributeName = lcfirst($commandName); - if (! array_key_exists($attributeName, $column->getAttributes()) - && ! $column->change - && ! $connection->usingNativeSchemaOperations()) { + if ($column->change || ! isset($column->{$attributeName})) { continue; } From 2d2f959aa0db2dc063e8d55e7f981bde4f791ae0 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Sun, 18 Dec 2022 14:25:44 +0330 Subject: [PATCH 10/19] force compiling fluent commands on native change --- src/Illuminate/Database/Schema/Blueprint.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 85db3212d2e6..69e2d75d5a8c 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -129,6 +129,15 @@ public function toSql(Connection $connection, Grammar $grammar) $this->ensureCommandsAreValid($connection); foreach ($this->commands as $command) { + if ($command->isFluent + && (! $command->column->change && ! isset($command->column->{lcfirst($command->name)}) + || ($command->column->change && ! $connection->usingNativeSchemaOperations()))) { + // Doctrine DBAL handles fluent commands on change. Also, there is no need to + // compile them when creating or adding a column when its value is not set, + // but we should always compile them when using native column modifying. + continue; + } + $method = 'compile'.ucfirst($command->name); if (method_exists($grammar, $method) || $grammar::hasMacro($method)) { @@ -247,16 +256,12 @@ public function addFluentCommands(Grammar $grammar) { foreach ($this->columns as $column) { foreach ($grammar->getFluentCommands() as $commandName) { - $attributeName = lcfirst($commandName); - - if ($column->change || ! isset($column->{$attributeName})) { - continue; - } + $value = $column->{lcfirst($commandName)}; - $value = $column->{$attributeName}; + $isFluent = true; $this->addCommand( - $commandName, compact('value', 'column') + $commandName, compact('value', 'column', 'isFluent') ); } } From a2278aadb93aec57929bc1c13cb15998d43d113c Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Sun, 18 Dec 2022 16:52:30 +0330 Subject: [PATCH 11/19] fix PostgreSQL storedAs exception --- .../Database/Schema/Grammars/PostgresGrammar.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index f370528cb59b..0c4f72c63d1d 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -1137,11 +1137,13 @@ protected function modifyIncrement(Blueprint $blueprint, Fluent $column) protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) { if ($column->change) { - if (array_key_exists('virtualAs', $column->getAttributes()) && is_null($column->virtualAs)) { - return 'drop expression if exists'; + if (array_key_exists('virtualAs', $column->getAttributes())) { + return is_null($column->virtualAs) + ? 'drop expression if exists' + : throw new LogicException('This database driver does not support modifying generated columns.'); } - throw new LogicException('This database driver does not support modifying generated columns.'); + return null; } if (! is_null($column->virtualAs)) { @@ -1159,11 +1161,13 @@ protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column) protected function modifyStoredAs(Blueprint $blueprint, Fluent $column) { if ($column->change) { - if (array_key_exists('storedAs', $column->getAttributes()) && is_null($column->storedAs)) { - return 'drop expression if exists'; + if (array_key_exists('storedAs', $column->getAttributes())) { + return is_null($column->storedAs) + ? 'drop expression if exists' + : throw new LogicException('This database driver does not support modifying generated columns.'); } - throw new LogicException('This database driver does not support modifying generated columns.'); + return null; } if (! is_null($column->storedAs)) { From c7e5250253c705cc002488d3e3d485abac33f6e9 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Mon, 19 Dec 2022 16:27:01 +0330 Subject: [PATCH 12/19] add native column modifying on SQL Server --- .../Schema/Grammars/SqlServerGrammar.php | 80 ++++++++++++++++++- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 4d7271ca3308..751694fb3ebf 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -29,6 +29,13 @@ class SqlServerGrammar extends Grammar */ protected $serials = ['tinyInteger', 'smallInteger', 'mediumInteger', 'integer', 'bigInteger']; + /** + * The commands to be executed outside of create or alter command. + * + * @var string[] + */ + protected $fluentCommands = ['Default']; + /** * Compile a create database command. * @@ -126,6 +133,43 @@ 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()) { + $changes = []; + + foreach ($blueprint->getChangedColumns() as $column) { + $sql = 'alter table '.$this->wrapTable($blueprint).' alter column '.$this->wrap($column); + + foreach ($this->modifiers as $modifier) { + if (in_array($modifier, ['Increment', 'Default'])) { + continue; + } + + if (method_exists($this, $method = "modify{$modifier}")) { + $sql .= $this->{$method}($blueprint, $column); + } + } + + $changes[] = $sql; + } + + return $changes; + } + + return parent::compileChange($blueprint, $command, $connection); + } + /** * Compile a primary key command. * @@ -190,6 +234,28 @@ public function compileSpatialIndex(Blueprint $blueprint, Fluent $command) ); } + /** + * Compile a default command. + * + * @param \Illuminate\Database\Schema\Blueprint $blueprint + * @param \Illuminate\Support\Fluent $command + * @return string|null + */ + public function compileDefault(Blueprint $blueprint, Fluent $command) + { + if ($command->column->change) { + $dropDefaultConstraintSql = $this->compileDropDefaultConstraint($blueprint, $command); + + return is_null($command->value) + ? $dropDefaultConstraintSql + : $dropDefaultConstraintSql.sprintf('alter table %s add default %s for %s', + $this->wrapTable($blueprint), + $this->getDefaultValue($command->default), + $this->wrap($command->column) + ); + } + } + /** * Compile a drop table command. * @@ -238,7 +304,7 @@ public function compileDropColumn(Blueprint $blueprint, Fluent $command) { $columns = $this->wrapArray($command->columns); - $dropExistingConstraintsSql = $this->compileDropDefaultConstraint($blueprint, $command).';'; + $dropExistingConstraintsSql = $this->compileDropDefaultConstraint($blueprint, $command); return $dropExistingConstraintsSql.'alter table '.$this->wrapTable($blueprint).' drop column '.implode(', ', $columns); } @@ -252,7 +318,7 @@ public function compileDropColumn(Blueprint $blueprint, Fluent $command) */ public function compileDropDefaultConstraint(Blueprint $blueprint, Fluent $command) { - $columns = "'".implode("','", $command->columns)."'"; + $columns = "'".implode("','", $command->columns ?? [$command->column->name])."'"; $tableName = $this->getTablePrefix().$blueprint->getTable(); @@ -260,7 +326,7 @@ public function compileDropDefaultConstraint(Blueprint $blueprint, Fluent $comma $sql .= "SELECT @sql += 'ALTER TABLE [dbo].[{$tableName}] DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' "; $sql .= 'FROM sys.columns '; $sql .= "WHERE [object_id] = OBJECT_ID('[dbo].[{$tableName}]') AND [name] in ({$columns}) AND [default_object_id] <> 0;"; - $sql .= 'EXEC(@sql)'; + $sql .= 'EXEC(@sql);'; return $sql; } @@ -936,6 +1002,14 @@ protected function modifyIncrement(Blueprint $blueprint, Fluent $column) */ protected function modifyPersisted(Blueprint $blueprint, Fluent $column) { + if ($column->change) { + if ($column->type === 'computed') { + return $column->persisted ? ' add persisted' : ' drop persisted'; + } + + return null; + } + if ($column->persisted) { return ' persisted'; } From f35597757f7dd18fa0ff20ec1b812de2089264f2 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 20 Dec 2022 01:05:51 +0330 Subject: [PATCH 13/19] better syntax for PostgreSQL --- .../Database/Schema/Grammars/PostgresGrammar.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 0c4f72c63d1d..9f4ed99995d9 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -163,12 +163,10 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) { if ($connection->usingNativeSchemaOperations()) { - $changes = []; + $columns = []; foreach ($blueprint->getChangedColumns() as $column) { - $sql = 'alter table '.$this->wrapTable($blueprint).' alter column '.$this->wrap($column); - - $changes[] = $sql.' type '.$this->getType($column).$this->modifyCollate($blueprint, $column); + $changes = ['type '.$this->getType($column).$this->modifyCollate($blueprint, $column)]; foreach ($this->modifiers as $modifier) { if (in_array($modifier, ['Collate', 'Increment'])) { @@ -180,13 +178,15 @@ public function compileChange(Blueprint $blueprint, Fluent $command, Connection $constraints = (array) $this->{$method}($blueprint, $column); foreach ($constraints as $constraint) { - $changes[] = $sql.' '.$constraint; + $changes[] = $constraint; } } } + + $columns[] = implode(', ', $this->prefixArray('alter column '.$this->wrap($column), $changes)); } - return $changes; + return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns); } return parent::compileChange($blueprint, $command, $connection); From b2ea87be547b9431c33aefdec729c75473224fe3 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 20 Dec 2022 01:08:08 +0330 Subject: [PATCH 14/19] support useCurrent and useCurrentOnUpdate --- .../Database/Schema/Grammars/MySqlGrammar.php | 44 ++++++++++++++----- .../Schema/Grammars/PostgresGrammar.php | 13 ++++-- .../Schema/Grammars/SQLiteGrammar.php | 7 ++- .../Schema/Grammars/SqlServerGrammar.php | 13 ++++-- .../DatabaseMySqlSchemaGrammarTest.php | 14 +++--- .../Database/DatabaseSchemaBlueprintTest.php | 16 +++---- 6 files changed, 71 insertions(+), 36 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 5c25f7ec2fbf..8db04f5d0e25 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -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; @@ -16,7 +17,7 @@ class MySqlGrammar extends Grammar */ protected $modifiers = [ 'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable', 'Invisible', - 'Srid', 'Default', 'Increment', 'Comment', 'After', 'First', + 'Srid', 'Default', 'OnUpdate', 'Increment', 'Comment', 'After', 'First', ]; /** @@ -235,9 +236,6 @@ public function compileChange(Blueprint $blueprint, Fluent $command, Connection $columns = []; foreach ($blueprint->getChangedColumns() as $column) { - // Each of the column types has their own compiler functions, which are tasked - // with turning the column definition into its SQL format for this platform - // used by the connection. The column's modifiers are compiled and added. $sql = $this->wrap($column).' '.$this->getType($column); $columns[] = $this->addModifiers($sql, $blueprint, $column); @@ -786,13 +784,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)); + } - return $column->useCurrentOnUpdate ? "$columnType on update $current" : $columnType; + if ($column->useCurrentOnUpdate) { + $column->onUpdate(new Expression($current)); + } + + return $column->precision ? "datetime($column->precision)" : 'datetime'; } /** @@ -836,13 +838,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)); + } + + if ($column->useCurrentOnUpdate) { + $column->onUpdate(new Expression($current)); + } - return $column->useCurrentOnUpdate ? "$columnType on update $current" : $columnType; + return $column->precision ? "timestamp($column->precision)" : 'timestamp'; } /** @@ -1203,6 +1209,20 @@ protected function modifyComment(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 a SRID column modifier. * diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index 9f4ed99995d9..8f486b5aa5e2 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -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 LogicException; @@ -873,9 +874,11 @@ protected function typeTimeTz(Fluent $column) */ protected function typeTimestamp(Fluent $column) { - $columnType = 'timestamp'.(is_null($column->precision) ? '' : "($column->precision)").' without time zone'; + if ($column->useCurrent) { + $column->default(new Expression('CURRENT_TIMESTAMP')); + } - return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; + return 'timestamp'.(is_null($column->precision) ? '' : "($column->precision)").' without time zone'; } /** @@ -886,9 +889,11 @@ protected function typeTimestamp(Fluent $column) */ protected function typeTimestampTz(Fluent $column) { - $columnType = 'timestamp'.(is_null($column->precision) ? '' : "($column->precision)").' with time zone'; + if ($column->useCurrent) { + $column->default(new Expression('CURRENT_TIMESTAMP')); + } - return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; + return 'timestamp'.(is_null($column->precision) ? '' : "($column->precision)").' with time zone'; } /** diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index c9d1c5503aaa..6d3f53f0eb15 100755 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -4,6 +4,7 @@ use Doctrine\DBAL\Schema\Index; use Illuminate\Database\Connection; +use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Arr; use Illuminate\Support\Fluent; @@ -727,7 +728,11 @@ protected function typeTimeTz(Fluent $column) */ protected function typeTimestamp(Fluent $column) { - return $column->useCurrent ? 'datetime default CURRENT_TIMESTAMP' : 'datetime'; + if ($column->useCurrent) { + $column->default(new Expression('CURRENT_TIMESTAMP')); + } + + return 'datetime'; } /** diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 751694fb3ebf..6d606e891ed9 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -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; @@ -763,9 +764,11 @@ protected function typeTimeTz(Fluent $column) */ protected function typeTimestamp(Fluent $column) { - $columnType = $column->precision ? "datetime2($column->precision)" : 'datetime'; + if ($column->useCurrent) { + $column->default(new Expression('CURRENT_TIMESTAMP')); + } - return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; + return $column->precision ? "datetime2($column->precision)" : 'datetime'; } /** @@ -778,9 +781,11 @@ protected function typeTimestamp(Fluent $column) */ protected function typeTimestampTz(Fluent $column) { - $columnType = $column->precision ? "datetimeoffset($column->precision)" : 'datetimeoffset'; + if ($column->useCurrent) { + $column->default(new Expression('CURRENT_TIMESTAMP')); + } - return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; + return $column->precision ? "datetimeoffset($column->precision)" : 'datetimeoffset'; } /** diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index 61ac2224caf8..1a64125870b6 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -837,7 +837,7 @@ public function testAddingDateTimeWithDefaultCurrent() $blueprint->dateTime('foo')->useCurrent(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table `users` add `foo` datetime default CURRENT_TIMESTAMP not null', $statements[0]); + $this->assertSame('alter table `users` add `foo` datetime not null default CURRENT_TIMESTAMP', $statements[0]); } public function testAddingDateTimeWithOnUpdateCurrent() @@ -846,7 +846,7 @@ public function testAddingDateTimeWithOnUpdateCurrent() $blueprint->dateTime('foo')->useCurrentOnUpdate(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table `users` add `foo` datetime on update CURRENT_TIMESTAMP not null', $statements[0]); + $this->assertSame('alter table `users` add `foo` datetime not null on update CURRENT_TIMESTAMP', $statements[0]); } public function testAddingDateTimeWithDefaultCurrentAndOnUpdateCurrent() @@ -855,7 +855,7 @@ public function testAddingDateTimeWithDefaultCurrentAndOnUpdateCurrent() $blueprint->dateTime('foo')->useCurrent()->useCurrentOnUpdate(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table `users` add `foo` datetime default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP not null', $statements[0]); + $this->assertSame('alter table `users` add `foo` datetime not null default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP', $statements[0]); } public function testAddingDateTimeWithDefaultCurrentOnUpdateCurrentAndPrecision() @@ -864,7 +864,7 @@ public function testAddingDateTimeWithDefaultCurrentOnUpdateCurrentAndPrecision( $blueprint->dateTime('foo', 3)->useCurrent()->useCurrentOnUpdate(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table `users` add `foo` datetime(3) default CURRENT_TIMESTAMP(3) on update CURRENT_TIMESTAMP(3) not null', $statements[0]); + $this->assertSame('alter table `users` add `foo` datetime(3) not null default CURRENT_TIMESTAMP(3) on update CURRENT_TIMESTAMP(3)', $statements[0]); } public function testAddingDateTimeTz() @@ -951,7 +951,7 @@ public function testAddingTimestampWithDefaultCurrentSpecifyingPrecision() $blueprint->timestamp('created_at', 1)->useCurrent(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table `users` add `created_at` timestamp(1) default CURRENT_TIMESTAMP(1) not null', $statements[0]); + $this->assertSame('alter table `users` add `created_at` timestamp(1) not null default CURRENT_TIMESTAMP(1)', $statements[0]); } public function testAddingTimestampWithOnUpdateCurrentSpecifyingPrecision() @@ -960,7 +960,7 @@ public function testAddingTimestampWithOnUpdateCurrentSpecifyingPrecision() $blueprint->timestamp('created_at', 1)->useCurrentOnUpdate(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table `users` add `created_at` timestamp(1) on update CURRENT_TIMESTAMP(1) not null', $statements[0]); + $this->assertSame('alter table `users` add `created_at` timestamp(1) not null on update CURRENT_TIMESTAMP(1)', $statements[0]); } public function testAddingTimestampWithDefaultCurrentAndOnUpdateCurrentSpecifyingPrecision() @@ -969,7 +969,7 @@ public function testAddingTimestampWithDefaultCurrentAndOnUpdateCurrentSpecifyin $blueprint->timestamp('created_at', 1)->useCurrent()->useCurrentOnUpdate(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertSame('alter table `users` add `created_at` timestamp(1) default CURRENT_TIMESTAMP(1) on update CURRENT_TIMESTAMP(1) not null', $statements[0]); + $this->assertSame('alter table `users` add `created_at` timestamp(1) not null default CURRENT_TIMESTAMP(1) on update CURRENT_TIMESTAMP(1)', $statements[0]); } public function testAddingTimestampTz() diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index 3e6ce17f5a43..45a72191faa6 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -113,16 +113,16 @@ public function testDefaultCurrentDateTime() $connection = m::mock(Connection::class); $blueprint = clone $base; - $this->assertEquals(['alter table `users` add `created` datetime default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new MySqlGrammar)); + $this->assertEquals(['alter table `users` add `created` datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new MySqlGrammar)); $blueprint = clone $base; - $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new PostgresGrammar)); + $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new PostgresGrammar)); $blueprint = clone $base; - $this->assertEquals(['alter table "users" add column "created" datetime default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new SQLiteGrammar)); + $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new SQLiteGrammar)); $blueprint = clone $base; - $this->assertEquals(['alter table "users" add "created" datetime default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new SqlServerGrammar)); + $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new SqlServerGrammar)); } public function testDefaultCurrentTimestamp() @@ -134,16 +134,16 @@ public function testDefaultCurrentTimestamp() $connection = m::mock(Connection::class); $blueprint = clone $base; - $this->assertEquals(['alter table `users` add `created` timestamp default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new MySqlGrammar)); + $this->assertEquals(['alter table `users` add `created` timestamp not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new MySqlGrammar)); $blueprint = clone $base; - $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new PostgresGrammar)); + $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new PostgresGrammar)); $blueprint = clone $base; - $this->assertEquals(['alter table "users" add column "created" datetime default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new SQLiteGrammar)); + $this->assertEquals(['alter table "users" add column "created" datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new SQLiteGrammar)); $blueprint = clone $base; - $this->assertEquals(['alter table "users" add "created" datetime default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new SqlServerGrammar)); + $this->assertEquals(['alter table "users" add "created" datetime not null default CURRENT_TIMESTAMP'], $blueprint->toSql($connection, new SqlServerGrammar)); } public function testUnsignedDecimalTable() From 6fb23dac7e5574b73211a6ffcdb5378f5acc59f5 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 20 Dec 2022 02:07:47 +0330 Subject: [PATCH 15/19] cleanup --- src/Illuminate/Database/Schema/Blueprint.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 69e2d75d5a8c..d97f842f1d51 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -129,11 +129,11 @@ public function toSql(Connection $connection, Grammar $grammar) $this->ensureCommandsAreValid($connection); foreach ($this->commands as $command) { - if ($command->isFluent + if (in_array($command->name, $grammar->getFluentCommands()) && (! $command->column->change && ! isset($command->column->{lcfirst($command->name)}) || ($command->column->change && ! $connection->usingNativeSchemaOperations()))) { // Doctrine DBAL handles fluent commands on change. Also, there is no need to - // compile them when creating or adding a column when its value is not set, + // compile them when creating or adding a column when its value is not set // but we should always compile them when using native column modifying. continue; } @@ -258,10 +258,8 @@ public function addFluentCommands(Grammar $grammar) foreach ($grammar->getFluentCommands() as $commandName) { $value = $column->{lcfirst($commandName)}; - $isFluent = true; - $this->addCommand( - $commandName, compact('value', 'column', 'isFluent') + $commandName, compact('value', 'column') ); } } From 4a15bb71bff29b882face31d2b451b2a0381cd09 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 20 Dec 2022 02:08:51 +0330 Subject: [PATCH 16/19] fix SQL server syntax --- .../Schema/Grammars/SqlServerGrammar.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 6d606e891ed9..5437f068917e 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -147,10 +147,14 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection) { if ($connection->usingNativeSchemaOperations()) { - $changes = []; + $columns = []; foreach ($blueprint->getChangedColumns() as $column) { - $sql = 'alter table '.$this->wrapTable($blueprint).' alter column '.$this->wrap($column); + $sql = sprintf('alter table %s alter column %s %s', + $this->wrapTable($blueprint), + $this->wrap($column), + $this->getType($column) + ); foreach ($this->modifiers as $modifier) { if (in_array($modifier, ['Increment', 'Default'])) { @@ -162,10 +166,10 @@ public function compileChange(Blueprint $blueprint, Fluent $command, Connection } } - $changes[] = $sql; + $columns[] = $sql; } - return $changes; + return $columns; } return parent::compileChange($blueprint, $command, $connection); @@ -247,11 +251,11 @@ public function compileDefault(Blueprint $blueprint, Fluent $command) if ($command->column->change) { $dropDefaultConstraintSql = $this->compileDropDefaultConstraint($blueprint, $command); - return is_null($command->value) + return is_null($command->column->default) ? $dropDefaultConstraintSql : $dropDefaultConstraintSql.sprintf('alter table %s add default %s for %s', $this->wrapTable($blueprint), - $this->getDefaultValue($command->default), + $this->getDefaultValue($command->column->default), $this->wrap($command->column) ); } From 8ecf5607e075f0c2c2a37439526bd3f958376be9 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 20 Dec 2022 02:09:20 +0330 Subject: [PATCH 17/19] add tests --- ...DatabaseSchemaBlueprintIntegrationTest.php | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php b/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php index b6b081496be4..8ad9439e6577 100644 --- a/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php +++ b/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php @@ -154,6 +154,145 @@ public function testDroppingColumnsWithoutDoctrineWorks() $this->assertEquals(['alter table "users" drop column "name"'], $blueprint->toSql($connection, new SQLiteGrammar)); } + public function testNativeColumnModifyingOnMySql() + { + $connection = $this->db->connection(); + $schema = $connection->getSchemaBuilder(); + + $schema->useNativeSchemaOperationsIfPossible(); + + $blueprint = new Blueprint('users', function ($table) { + $table->double('amount', 6, 2)->nullable()->invisible()->after('name')->change(); + $table->timestamp('added_at', 4)->nullable(false)->useCurrent()->useCurrentOnUpdate()->change(); + $table->enum('difficulty', ['easy', 'hard'])->default('easy')->charset('utf8mb4')->collation('unicode')->change(); + $table->multiPolygon('positions')->srid(1234)->storedAs('expression')->change(); + $table->bigIncrements('id')->first()->from(10)->comment('my comment')->change(); + }); + + $this->assertEquals([ + 'alter table `users` ' + .'modify `amount` double(6, 2) null invisible after `name`, ' + .'modify `added_at` timestamp(4) not null default CURRENT_TIMESTAMP(4) on update CURRENT_TIMESTAMP(4), ' + ."modify `difficulty` enum('easy', 'hard') character set utf8mb4 collate 'unicode' not null default 'easy', " + ."modify `positions` multipolygon as (expression) stored srid 1234, " + ."modify `id` bigint unsigned not null auto_increment primary key comment 'my comment' first", + 'alter table `users` auto_increment = 10', + ], $blueprint->toSql($connection, new MySqlGrammar)); + } + + public function testNativeColumnModifyingOnPostgreSql() + { + $connection = $this->db->connection(); + $schema = $connection->getSchemaBuilder(); + + $schema->useNativeSchemaOperationsIfPossible(); + + $blueprint = new Blueprint('users', function ($table) { + $table->integer('code')->autoIncrement()->from(10)->comment('my comment')->change(); + }); + + $this->assertEquals([ + 'alter table "users" ' + .'alter column "code" type serial, ' + .'alter column "code" set not null, ' + .'alter column "code" drop default, ' + .'alter column "code" drop identity if exists', + 'alter sequence users_code_seq restart with 10', + 'comment on column "users"."code" is \'my comment\'', + ], $blueprint->toSql($connection, new PostgresGrammar)); + + $blueprint = new Blueprint('users', function ($table) { + $table->char('name', 40)->nullable()->default('easy')->collation('unicode')->change(); + }); + + $this->assertEquals([ + 'alter table "users" ' + .'alter column "name" type char(40) collate "unicode", ' + .'alter column "name" drop not null, ' + .'alter column "name" set default \'easy\', ' + .'alter column "name" drop identity if exists', + 'comment on column "users"."name" is NULL', + ], $blueprint->toSql($connection, new PostgresGrammar)); + + $blueprint = new Blueprint('users', function ($table) { + $table->integer('foo')->generatedAs('expression')->always()->change(); + }); + + $this->assertEquals([ + 'alter table "users" ' + .'alter column "foo" type integer, ' + .'alter column "foo" set not null, ' + .'alter column "foo" drop default, ' + .'alter column "foo" drop identity if exists, ' + .'alter column "foo" add generated always as identity (expression)', + 'comment on column "users"."foo" is NULL', + ], $blueprint->toSql($connection, new PostgresGrammar)); + + $blueprint = new Blueprint('users', function ($table) { + $table->point('foo')->isGeometry()->projection(1234)->change(); + }); + + $this->assertEquals([ + 'alter table "users" ' + .'alter column "foo" type geometry(point, 1234), ' + .'alter column "foo" set not null, ' + .'alter column "foo" drop default, ' + .'alter column "foo" drop identity if exists', + 'comment on column "users"."foo" is NULL', + ], $blueprint->toSql($connection, new PostgresGrammar)); + + $blueprint = new Blueprint('users', function ($table) { + $table->timestamp('added_at', 2)->useCurrent()->storedAs(null)->change(); + }); + + $this->assertEquals([ + 'alter table "users" ' + .'alter column "added_at" type timestamp(2) without time zone, ' + .'alter column "added_at" set not null, ' + .'alter column "added_at" set default CURRENT_TIMESTAMP, ' + .'alter column "added_at" drop expression if exists, ' + .'alter column "added_at" drop identity if exists', + 'comment on column "users"."added_at" is NULL', + ], $blueprint->toSql($connection, new PostgresGrammar)); + } + + public function testNativeColumnModifyingOnSqlServer() + { + $connection = $this->db->connection(); + $schema = $connection->getSchemaBuilder(); + + $schema->useNativeSchemaOperationsIfPossible(); + + $blueprint = new Blueprint('users', function ($table) { + $table->timestamp('added_at', 4)->nullable(false)->useCurrent()->change(); + }); + + $this->assertEquals([ + 'alter table "users" alter column "added_at" datetime2(4) not null', + "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE [dbo].[users] DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID('[dbo].[users]') AND [name] in ('added_at') AND [default_object_id] <> 0;EXEC(@sql);" + .'alter table "users" add default CURRENT_TIMESTAMP for "added_at"', + ], $blueprint->toSql($connection, new SqlServerGrammar)); + + $blueprint = new Blueprint('users', function ($table) { + $table->char('name', 40)->nullable()->default('easy')->collation('unicode')->change(); + }); + + $this->assertEquals([ + 'alter table "users" alter column "name" nchar(40) collate unicode null', + "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE [dbo].[users] DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID('[dbo].[users]') AND [name] in ('name') AND [default_object_id] <> 0;EXEC(@sql);" + .'alter table "users" add default \'easy\' for "name"', + ], $blueprint->toSql($connection, new SqlServerGrammar)); + + $blueprint = new Blueprint('users', function ($table) { + $table->integer('foo')->change(); + }); + + $this->assertEquals([ + 'alter table "users" alter column "foo" int not null', + "DECLARE @sql NVARCHAR(MAX) = '';SELECT @sql += 'ALTER TABLE [dbo].[users] DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' FROM sys.columns WHERE [object_id] = OBJECT_ID('[dbo].[users]') AND [name] in ('foo') AND [default_object_id] <> 0;EXEC(@sql);", + ], $blueprint->toSql($connection, new SqlServerGrammar)); + } + public function testChangingColumnWithCollationWorks() { $this->db->connection()->getSchemaBuilder()->create('users', function ($table) { From 56002bf861b95caefeeff97f2a078d048c79ccac Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 20 Dec 2022 02:35:36 +0330 Subject: [PATCH 18/19] fix code style --- tests/Database/DatabaseSchemaBlueprintIntegrationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php b/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php index 8ad9439e6577..5829f382c65c 100644 --- a/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php +++ b/tests/Database/DatabaseSchemaBlueprintIntegrationTest.php @@ -174,7 +174,7 @@ public function testNativeColumnModifyingOnMySql() .'modify `amount` double(6, 2) null invisible after `name`, ' .'modify `added_at` timestamp(4) not null default CURRENT_TIMESTAMP(4) on update CURRENT_TIMESTAMP(4), ' ."modify `difficulty` enum('easy', 'hard') character set utf8mb4 collate 'unicode' not null default 'easy', " - ."modify `positions` multipolygon as (expression) stored srid 1234, " + .'modify `positions` multipolygon as (expression) stored srid 1234, ' ."modify `id` bigint unsigned not null auto_increment primary key comment 'my comment' first", 'alter table `users` auto_increment = 10', ], $blueprint->toSql($connection, new MySqlGrammar)); From 0a881dd9e29c119f42e62532d4cdec483958709e Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Wed, 21 Dec 2022 14:51:56 +0330 Subject: [PATCH 19/19] use cleaner syntax --- src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 8db04f5d0e25..fb11ce2ddf7b 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -236,13 +236,12 @@ public function compileChange(Blueprint $blueprint, Fluent $command, Connection $columns = []; foreach ($blueprint->getChangedColumns() as $column) { - $sql = $this->wrap($column).' '.$this->getType($column); + $sql = 'modify '.$this->wrap($column).' '.$this->getType($column); $columns[] = $this->addModifiers($sql, $blueprint, $column); } - return 'alter table '.$this->wrapTable($blueprint).' ' - .implode(', ', $this->prefixArray('modify', $columns)); + return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns); } return parent::compileChange($blueprint, $command, $connection);