Skip to content

fix(postgres): resolve enum column change syntax error #56523

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

Draft
wants to merge 3 commits into
base: 12.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,15 @@ public function compileAutoIncrementStartingValues(Blueprint $blueprint, Fluent
public function compileChange(Blueprint $blueprint, Fluent $command)
{
$column = $command->column;
$statements = [];

if ($column->type === 'enum') {
$constraintName = $blueprint->getTable().'_'.$column->name.'_check';
$statements[] = sprintf('alter table %s drop constraint if exists %s',
$this->wrapTable($blueprint),
$this->wrap($constraintName)
);
}

$changes = ['type '.$this->getType($column).$this->modifyCollate($blueprint, $column)];

Expand All @@ -298,10 +307,23 @@ public function compileChange(Blueprint $blueprint, Fluent $command)
}
}

return sprintf('alter table %s %s',
$statements[] = sprintf('alter table %s %s',
$this->wrapTable($blueprint),
implode(', ', $this->prefixArray('alter column '.$this->wrap($column), $changes))
);

if ($column->type === 'enum') {
$constraintName = $blueprint->getTable().'_'.$column->name.'_check';
$statements[] = sprintf('alter table %s add constraint %s check ("%s" in (%s))',
$this->wrapTable($blueprint),
$this->wrap($constraintName),
$column->name,
$this->quoteString($column->allowed)
);
}

// Return single statement or array of statements
return count($statements) === 1 ? $statements[0] : $statements;
}

/**
Expand Down Expand Up @@ -922,6 +944,10 @@ protected function typeBoolean(Fluent $column)
*/
protected function typeEnum(Fluent $column)
{
if ($column->change) {
return 'varchar(255)';
}

return sprintf(
'varchar(255) check ("%s" in (%s))',
$column->name,
Expand Down
22 changes: 22 additions & 0 deletions tests/Database/DatabasePostgresSchemaGrammarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,28 @@ public function testDropAllDomainsWithPrefixAndSchema()
$this->assertSame('drop domain "schema"."alpha", "schema"."beta", "schema"."gamma" cascade', $statement);
}

public function testNativeColumnModifyingOnPostgres()
{
$blueprint = new Blueprint($this->getConnection(), 'tasks', function ($table) {
$table->enum('status', ['pending', 'queued'])->default('pending')->change();
});

$statements = $blueprint->toSql();

$this->assertCount(4, $statements);

$this->assertStringContainsString('drop constraint if exists "tasks_status_check"', $statements[0]);

$this->assertStringContainsString('alter table "tasks" alter column "status" type varchar(255)', $statements[1]);
$this->assertStringNotContainsString('check (', $statements[1]);
$this->assertStringContainsString('set default \'pending\'', $statements[1]);
$this->assertStringContainsString('set not null', $statements[1]);

$this->assertStringContainsString('add constraint "tasks_status_check" check ("status" in (\'pending\', \'queued\'))', $statements[2]);

$this->assertStringContainsString('comment on column', $statements[3]);
}

public function testCompileColumns()
{
$connection = $this->getConnection();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Illuminate\Tests\Integration\Database\Postgres;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use PHPUnit\Framework\Attributes\RequiresOperatingSystem;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;

#[RequiresOperatingSystem('Linux|Darwin')]
#[RequiresPhpExtension('pdo_pgsql')]
class DatabasePostgresSchemaBuilderAlterTableWithEnumTest extends PostgresTestCase
{
protected function afterRefreshingDatabase()
{
Schema::create('orders', function (Blueprint $table) {
$table->integer('id');
$table->string('name');
$table->enum('status', ['pending', 'processing'])->default('pending');
});
}

protected function destroyDatabaseMigrations()
{
Schema::drop('orders');
}

public function testChangeEnumColumnValues()
{
Schema::table('orders', function (Blueprint $table) {
$table->enum('status', ['pending', 'queued'])->default('pending')->change();
});

$this->assertTrue(Schema::hasColumn('orders', 'status'));
$this->assertSame('varchar', Schema::getColumnType('orders', 'status'));
}

public function testRenameColumnOnTableWithEnum()
{
Schema::table('orders', function (Blueprint $table) {
$table->renameColumn('name', 'title');
});

$this->assertTrue(Schema::hasColumn('orders', 'title'));
}

public function testChangeNonEnumColumnOnTableWithEnum()
{
Schema::table('orders', function (Blueprint $table) {
$table->unsignedInteger('id')->change();
});

$this->assertSame('int4', Schema::getColumnType('orders', 'id'));
}
}