-
Notifications
You must be signed in to change notification settings - Fork 11.2k
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
Schema builder: Dropping a column with a default value constraint #4402
Comments
I'm not that familiar with SQL Server. If you want to submit a pull request to fix this behavior please feel free. |
I've stumbled upon the same issue today. Creating a column with a default value on SQL Server creates a constraint that stops the ability to drop the column. |
Column name change also generates an error... |
any update on this? it's happening on laravel 5.1 and mssql. it's fine if you use Schema::drop() but the error occurs when you use $table->dropColumn(). |
Temporary solution:
But more complete solution is to assign explicit name to default contraint as described in #8827 (this requires developing a pull request - anyone please?). |
I just ran into this problem as well. Why was this issue closed? Edit: I just did some research and found this piece of code which fetches all constraints for a list of columns. SELECT OBJECT_NAME([default_object_id])
FROM SYS.COLUMNS
WHERE [object_id] = OBJECT_ID('[tableSchema].[tableSchema]') AND [name] IN ('column1', 'column2', 'column3'); This can be used in conjunction with $sqlConstraints = count($constraints) ? ' drop constraint ' . implode(', ', $constraints) . ',' : '';
return sprintf('alter table %s%s drop column %s',
$this->wrapTable($blueprint),
$sqlConstraints,
implode(', ', $columns)
); It just doesn't seem like the right place to put it, but I don't know where else it could be placed. |
Just another note to say I just had this issue with Sql Server and the solution in @rafis comment fixed it, but it does seem somewhat janky. |
Hi, today I run into this problem as well, I wish to have this functionality work from Laravel just like with other database driver. |
This is sadly still an issue, and I hope it will be addressed in the future. Illuminate\Foundation\Testing\RefreshDatabase for testing will not work either, of course. |
Inspired by @holystix solution in their referenced fix, I made a Blueprint macro to drop the default constraint without polluting the migration files. use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
Blueprint::macro('dropDefaultConstraint', function (string $column) {
$connection = Schema::getConnection();
if ($connection->getDriverName() === 'sqlsrv') {
$query = sprintf(
'SELECT OBJECT_NAME([default_object_id]) AS name ' .
'FROM SYS.COLUMNS ' .
"WHERE [object_id] = OBJECT_ID('[dbo].[%s]') AND [name] = '%s'",
$this->getTable(),
$column
);
$result = $connection->selectOne($query);
$constraint = new \Doctrine\DBAL\Schema\Index($result->name, [$column]);
$connection->getDoctrineSchemaManager()->dropConstraint($constraint, $this->getTable());
}
}); Just put it in |
This macro throws an exception.
|
But good news is i managed to fix your code. This version works for me. $databaseConnectionName = 'my-mssql-connection';
Blueprint::macro('dropDefaultConstraint', function (string $column) use ($databaseConnectionName) {
$connection = Schema::connection($databaseConnectionName)->getConnection();
if ($connection->getDriverName() === 'sqlsrv') {
$query = sprintf(
'SELECT OBJECT_NAME([default_object_id]) AS name ' .
'FROM SYS.COLUMNS ' .
"WHERE [object_id] = OBJECT_ID('[dbo].[%s]') AND [name] = '%s'",
$this->getTable(),
$column
);
$result = $connection->selectOne($query);
$constraint = new Index($result->name, [$column]);
$tableName = $this->getTable();
$keyName = $constraint->getName();
$sql = "ALTER TABLE {$tableName} DROP CONSTRAINT {$keyName}";
$connection->statement($sql);
//$connection->getDoctrineSchemaManager()->dropConstraint($constraint, $this->getTable());
}
}); |
Why is this not in the default? should be checked when drop column happens in laravel. This issue shouldn't be closed, its still an issue to date. |
Here you have a better fix, it works as long as you only use one drop column statement with array notation: class SqlServerGrammarFixed extends SqlServerGrammar
{
public function compileDropColumn(Blueprint $blueprint, Fluent $command)
{
echo 'testsetst';
$dropConstraintsSql = $this->compileDropDefaultConstraint($blueprint, $command);
$base = parent::compileDropColumn($blueprint, $command);
Log::debug($dropConstraintsSql);
return $dropConstraintsSql . '; ' . $base;
}
protected function compileDropDefaultConstraint(Blueprint $blueprint, Fluent $command)
{
$sql = "DECLARE @sql NVARCHAR(MAX) = '';";
$tableName = $blueprint->getTable();
$columns = $this->wrapArray($command->columns);
Log::info($columns);
$columnSql = "'" . implode("','", $command->columns) . "'";
$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 ($columnSql);";
$sql .= 'EXEC(@sql)';
return $sql;
}
}
class SqlServerConnectionFixed extends SqlServerConnection
{
protected function getDefaultSchemaGrammar()
{
return $this->withTablePrefix(new SqlServerGrammarFixed());
}
}
IN DatabaseServiceProvider.php Connection::resolverFor('sqlsrv', function ($connection, $database, $prefix, $config) {
return new SqlServerConnectionFixed($connection, $database, $prefix, $config);
}); |
I am confused. I am using Laravel 6.0.4 and facing this 6 years old issue. Any updates when it will be fixed? |
It looks like there is a PR proposed in #31229 |
@yaroslavmo see my comment for quick fix for now, until hopefully they will actually approve one of my PR's (upto now all my Pr's have been instantly denied/closed). |
Thank you. I used the workaround @rafis suggested (only on the local machine). I will wait till they review your PR. I strongly believe this kind of thing should be the same for all four DB connectors Laravel supports and should be fixed on the framework level. For now, it is hard to use sqlsrv as a database. P.S. if they deny your PR, I will have to use your fix tho 😃 |
It has been merged. will probably be release in next laravel version |
Hi @joelharkes . Your PR did not work for one of my migrations.
It gives this error:
I tried to debug it myself but I am not that familiar with SQL Server and it is super unclear to me why created default object is called 'DF__cors_conf__suppo__44428990' and not 'DF__cors_conf__supports_credentials__44428990' |
This is the SQL query generated by your PR:
Which fails with the same error when I run it in SQL Server Management Studio.
This will also work if I just add "not equals": |
Weird let me check if I can reproduce it tomorrow. |
I'm using Laravel 4.1 with the
sqlsrv
database driver and I'm running in a problem with the default value constraints in the migration scripts.When I add a column to a table with a default value constraint the name of the constraint is randomly generated (e.g.
DF__foo__bar__322242A7
). The problem occurs now in the rollback method because it is not possible to drop the column as long as the default constraint exists and it is not possible to drop the constraint because its name is randomly generated by the sql server.I think that it would be good if the Laravel framework would generate the names of default value constraints like id does it for the primary, the foreign and the unique constraints.
The text was updated successfully, but these errors were encountered: