Skip to content

Fix SqlServerAdapter returning empty string instead of null for column default#2090

Merged
MasterOdin merged 4 commits intocakephp:0.xfrom
reeperbahnause:patch-2
Jul 9, 2022
Merged

Fix SqlServerAdapter returning empty string instead of null for column default#2090
MasterOdin merged 4 commits intocakephp:0.xfrom
reeperbahnause:patch-2

Conversation

@reeperbahnause
Copy link
Copy Markdown
Contributor

The SqlServerAdapter::parseDefault($default) function returns "" if $default is null
Because of the returned empty string, the column can not be changed to have an empty string as default value (no differnce detected)

Example for an existing column which has no effect:

$this->table('tableName')->changeColumn('columnName', 'string', ['default' => '', 'null' => false])

The `SqlServerAdapter::parseDefault($default)` function returns `""` if $default is `null`
Because of the returned empty string, the column can not be changed to have an empty string as default value (no differnce detected)
@MasterOdin
Copy link
Copy Markdown
Member

MasterOdin commented Apr 25, 2022

What version of SQLServer are you using, and how are you getting a column that has $default === null? Just want to understand where the current test I'd expect to catch this:

public function testChangeColumnDefaultToNull()
{
$table = new \Phinx\Db\Table('t', [], $this->adapter);
$table->addColumn('column1', 'string', ['null' => true, 'default' => 'test'])
->save();
$newColumn1 = new \Phinx\Db\Table\Column();
$newColumn1
->setType('string')
->setDefault(null);
$table->changeColumn('column1', $newColumn1)->save();
$columns = $this->adapter->getColumns('t');
$this->assertNull($columns['column1']->getDefault());
}

is failing as it should be that the assertNull on the last line would fail?

@reeperbahnause
Copy link
Copy Markdown
Contributor Author

The SQL Server version is 15.0.2000

And the statement which was executed by phinx to get the current table structure was this (SqlServerAdapter::getColumns()):

SELECT DISTINCT TABLE_SCHEMA AS [schema], TABLE_NAME as [table_name], COLUMN_NAME AS [name], DATA_TYPE AS [type],
            IS_NULLABLE AS [null], COLUMN_DEFAULT AS [default],
            CHARACTER_MAXIMUM_LENGTH AS [char_length],
            NUMERIC_PRECISION AS [precision],
            NUMERIC_SCALE AS [scale], ORDINAL_POSITION AS [ordinal_position],
            COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') as [identity]
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'tableName'
        ORDER BY ordinal_position

@MasterOdin
Copy link
Copy Markdown
Member

Sorry, when I said "how are you getting the column", I meant the phinx command that you were using to create the column, or is the column coming from somewhere else initially?

I'd like to make sure we have a test here for this code change, just not sure what to suggest for such a test and trying to gain a better understanding of the issue.

@reeperbahnause
Copy link
Copy Markdown
Contributor Author

The tabe is initialy created like this:

$table = $this->table('users');
        $table->addColumn('login', 'string', array('limit' => 50))
            ->addColumn('firstname', 'string', array('limit' => 100))
            ->addColumn('lastname', 'string', array('limit' => 100))
            ->addColumn('status', 'string', array('limit' => 45))
            ->addColumn('hash', 'string', array('limit' => 255))
            ->addColumn('email', 'string', array('limit' => 255))
            ->addColumn('network', 'string', array('limit' => 255))
            ->addColumn('networkid', 'string', array('limit' => 255))
            ->addColumn('profileurl', 'string', array('limit' => 255))
            ->addColumn('imageurl', 'string', array('limit' => 255))
            ->addColumn('company', 'string', array('limit' => 255))
            ->addColumn('position', 'string', array('limit' => 255))
            ->addColumn('country', 'string', array('limit' => 255))
            ->addColumn('city', 'string', array('limit' => 255))
            ->addColumn('street', 'string', array('limit' => 255))
            ->addColumn('resettoken', 'string', array('limit' => 64, 'null' => true))
            ->create();

and the migration which did not have any effect was this:

$table = $this->table('users');
        $table->changeColumn('status', 'string', ['default' => '', 'null' => false])
            ->changeColumn('network', 'string', ['default' => '', 'null' => false])
            ->changeColumn('networkid', 'string', ['default' => '', 'null' => false])
            ->changeColumn('profileurl', 'string', ['default' => '', 'null' => false])
            ->changeColumn('imageurl', 'string', ['default' => '', 'null' => false])
            ->changeColumn('company', 'string', ['default' => '', 'null' => false])
            ->changeColumn('position', 'string', ['default' => '', 'null' => false])
            ->changeColumn('country', 'string', ['default' => '', 'null' => false])
            ->changeColumn('street', 'string', ['default' => '', 'null' => false])
            ->changeColumn('resettoken', 'string', ['default' => '', 'null'=>true])
            ->changeColumn('city', 'string', ['default' => '', 'null' => false])
        ->update();

Does that help?
If not let me know. I will get back in an hour.

@reeperbahnause
Copy link
Copy Markdown
Contributor Author

Can I provide any more information regarding this issue?

Comment thread src/Phinx/Db/Adapter/SqlServerAdapter.php
Signed-off-by: Matthew Peveler <matt.peveler@gmail.com>
Signed-off-by: Matthew Peveler <matt.peveler@gmail.com>
@MasterOdin MasterOdin changed the title SqlServerAdapter::parseDefault Fix SqlServerAdapter::parseDefault returning empty string instead of null Jul 9, 2022
@MasterOdin MasterOdin changed the title Fix SqlServerAdapter::parseDefault returning empty string instead of null Fix SqlServerAdapter returning empty string instead of null for column default Jul 9, 2022
Copy link
Copy Markdown
Member

@MasterOdin MasterOdin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay in getting to this @reeperbahnause! I've added a test case that verifies the change and made some slight tweaks, but the fix looks good. Seems like the bug was around that a NOT NULL column with no default would have a null value for column_default, while a NULL column with a null default would have "(NULL)" for column_default. I'm sure there's some important reason for this, but weird nevertheless.

This should be put out in a release soon.

@MasterOdin MasterOdin merged commit 9a6ce1e into cakephp:0.x Jul 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants