From 0c060ecd1fa7efd55538df91833680fac8ddc06c Mon Sep 17 00:00:00 2001 From: Matthew Peveler Date: Tue, 12 Oct 2021 00:12:43 -1000 Subject: [PATCH] Fix changing boolean column option's in postgresql Signed-off-by: Matthew Peveler --- src/Phinx/Db/Adapter/PostgresAdapter.php | 22 +++++++------ .../Phinx/Db/Adapter/PostgresAdapterTest.php | 33 ++++++++++++++++--- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/Phinx/Db/Adapter/PostgresAdapter.php b/src/Phinx/Db/Adapter/PostgresAdapter.php index 67d0842c5..b9b637d94 100644 --- a/src/Phinx/Db/Adapter/PostgresAdapter.php +++ b/src/Phinx/Db/Adapter/PostgresAdapter.php @@ -537,26 +537,27 @@ protected function getRenameColumnInstructions($tableName, $columnName, $newColu */ protected function getChangeColumnInstructions($tableName, $columnName, Column $newColumn) { + $quotedColumnName = $this->quoteColumnName($columnName); $instructions = new AlterInstructions(); if ($newColumn->getType() === 'boolean') { - $sql = sprintf('ALTER COLUMN %s DROP DEFAULT', $this->quoteColumnName($columnName)); + $sql = sprintf('ALTER COLUMN %s DROP DEFAULT', $quotedColumnName); $instructions->addAlter($sql); } $sql = sprintf( 'ALTER COLUMN %s TYPE %s', - $this->quoteColumnName($columnName), + $quotedColumnName, $this->getColumnSqlDefinition($newColumn) ); if (in_array($newColumn->getType(), ['smallinteger', 'integer', 'biginteger'], true)) { $sql .= sprintf( ' USING (%s::bigint)', - $this->quoteColumnName($columnName) + $quotedColumnName ); } if ($newColumn->getType() === 'uuid') { $sql .= sprintf( ' USING (%s::uuid)', - $this->quoteColumnName($columnName) + $quotedColumnName ); } //NULL and DEFAULT cannot be set while changing column type @@ -566,8 +567,9 @@ protected function getChangeColumnInstructions($tableName, $columnName, Column $ $sql = preg_replace('/DEFAULT .*/', '', $sql); if ($newColumn->getType() === 'boolean') { $sql .= sprintf( - ' USING (CASE WHEN %s=0 THEN FALSE ELSE TRUE END)', - $this->quoteColumnName($columnName) + ' USING (CASE WHEN %s IS NULL THEN NULL WHEN %s::int=0 THEN FALSE ELSE TRUE END)', + $quotedColumnName, + $quotedColumnName ); } $instructions->addAlter($sql); @@ -575,7 +577,7 @@ protected function getChangeColumnInstructions($tableName, $columnName, Column $ // process null $sql = sprintf( 'ALTER COLUMN %s', - $this->quoteColumnName($columnName) + $quotedColumnName ); if ($newColumn->isNull()) { @@ -589,14 +591,14 @@ protected function getChangeColumnInstructions($tableName, $columnName, Column $ if ($newColumn->getDefault() !== null) { $instructions->addAlter(sprintf( 'ALTER COLUMN %s SET %s', - $this->quoteColumnName($columnName), + $quotedColumnName, $this->getDefaultValueDefinition($newColumn->getDefault(), $newColumn->getType()) )); } else { //drop default $instructions->addAlter(sprintf( 'ALTER COLUMN %s DROP DEFAULT', - $this->quoteColumnName($columnName) + $quotedColumnName )); } @@ -605,7 +607,7 @@ protected function getChangeColumnInstructions($tableName, $columnName, Column $ $instructions->addPostStep(sprintf( 'ALTER TABLE %s RENAME COLUMN %s TO %s', $this->quoteTableName($tableName), - $this->quoteColumnName($columnName), + $quotedColumnName, $this->quoteColumnName($newColumn->getName()) )); } diff --git a/tests/Phinx/Db/Adapter/PostgresAdapterTest.php b/tests/Phinx/Db/Adapter/PostgresAdapterTest.php index 3461966e8..5c89ff589 100644 --- a/tests/Phinx/Db/Adapter/PostgresAdapterTest.php +++ b/tests/Phinx/Db/Adapter/PostgresAdapterTest.php @@ -859,6 +859,29 @@ public function testChangeColumnFromTextToInteger($type, $value) $this->assertSame($value, $row['column1']); } + public function testChangeBooleanOptions() + { + $table = new \Phinx\Db\Table('t', ['id' => false], $this->adapter); + $table->addColumn('my_bool', 'boolean', ['default' => true, 'null' => true]) + ->create(); + $table + ->insert([ + ['my_bool' => true], + ['my_bool' => false], + ['my_bool' => null], + ]) + ->update(); + $table->changeColumn('my_bool', 'boolean', ['default' => false, 'null' => true])->update(); + $columns = $this->adapter->getColumns('t'); + $this->assertStringContainsString('false', $columns[0]->getDefault()); + + $rows = $this->adapter->fetchAll('SELECT * FROM t'); + $this->assertCount(3, $rows); + $this->assertSame([true, false, null], array_map(function ($row) { + return $row['my_bool']; + }, $rows)); + } + public function testChangeColumnFromIntegerToBoolean() { $table = new \Phinx\Db\Table('t', [], $this->adapter); @@ -1058,8 +1081,8 @@ public function testAddIndexWithSort() LEFT JOIN LATERAL unnest (i.indoption) WITH ORDINALITY AS o (option, ordinality) ON c.ordinality = o.ordinality JOIN pg_attribute AS a ON trel.oid = a.attrelid AND a.attnum = c.colnum - WHERE trel.relname = 'table1' - AND irel.relname = 'table1_email_username' + WHERE trel.relname = 'table1' + AND irel.relname = 'table1_email_username' AND a.attname = 'email' GROUP BY o.option, tnsp.nspname, trel.relname, irel.relname"); $emailOrder = $rows[0]; @@ -1097,14 +1120,14 @@ public function testAddIndexWithIncludeColumns() ->save(); $this->assertTrue($table->hasIndexByName('table1_include_idx')); $rows = $this->adapter->fetchAll("SELECT CASE WHEN attnum <= indnkeyatts THEN 'KEY' ELSE 'INCLUDED' END as index_column - FROM pg_index ix + FROM pg_index ix JOIN pg_class t ON ix.indrelid = t.oid JOIN pg_class i ON ix.indexrelid = i.oid - JOIN pg_attribute a ON i.oid = a.attrelid + JOIN pg_attribute a ON i.oid = a.attrelid JOIN pg_namespace nsp ON t.relnamespace = nsp.oid WHERE nsp.nspname = 'public' AND t.relkind = 'r' - AND t.relname = 'table1' + AND t.relname = 'table1' AND a.attname = 'email'"); $indexColumn = $rows[0]; $this->assertEquals($indexColumn['index_column'], 'KEY');