Skip to content

Bug: [SQLite3] Forge class modifyColumn() method seriously messes up sqlite3 table #8410

Closed
@dgvirtual

Description

@dgvirtual

PHP Version

8.1

CodeIgniter4 Version

4.4.4

CodeIgniter4 Installation Method

Composer (using codeigniter4/appstarter)

Which operating systems have you tested for this bug?

Linux

Which server did you use?

cli-server (PHP built-in webserver)

Database

SQLite3

What happened?

Changing a single table column name results in modifications of multiple columns, both column constraints (for example, turning NOT NULL fields to NULL) and defaults (0 to '0', NULL to 'NULL', etc) get changed.

Steps to Reproduce

Start with empty project.
Rename env to .env, change these lines in it to the values:

app.baseURL = 'http://localhost:8080/'
database.default.database = ci4
database.default.DBDriver = SQLite3

Add a cli route in app/Config/Routes.php:

$routes->cli('home', 'Home::index');

Add migration for a table:

php spark make:migration CreateTestTable

Replace up() and down() methods with:

    public function up()
    {
        $this->forge->addField([
            'id' => [
                'type'           => 'INT',
                'constraint'     => 10,
                'auto_increment' => true,
                'null'           => false,
            ],
            'user_id' => [
                'type'       => 'INT',
                'constraint' => 10,
                'null'       => false,
            ],
            'month' => [
                'type'       => 'VARCHAR',
                'constraint' => 7,
                'null'       => false,
            ],
            'invoice_series' => [
                'type'       => 'VARCHAR',
                'constraint' => 10,
                'null'       => false,
            ],
            'total' => [
                'type' => 'DECIMAL',
                'null' => false,
            ],
            'paid' => [
                'type'    => 'TINYINT',
                'default' => 0,
            ],
            'paid_date' => [
                'type'       => 'VARCHAR',
                'constraint' => 10,
                'default'    => null,
            ],
            'created_at' => [
                'type' => 'DATETIME',
                'null' => false,
            ],
            'updated_at' => [
                'type' => 'DATETIME',
                'null' => false,
            ],
        ]);

        $this->forge->addKey('id', true);
        $this->forge->createTable('invoices');
    }

    public function down()
    {
        $this->forge->dropTable('invoices');
    }

Add test code to the Home controller, replace the index() method with:

public function index()
{

    $forge = \Config\Database::forge();

    $fields = [
        'invoice_series' => [
            'name'       => 'series',
            'type'       => 'VARCHAR',
            'constraint' => 10,
            'null'       => false,
        ],
    ];

    $forge->modifyColumn('invoices', $fields);

}

Now you can run the tests; here is what I do and what I get:

dg@tvenkinys:~/Programavimas/MOK/ci4bugDemo$ php spark migrate

CodeIgniter v4.4.4 Command Line Tool - Server Time: 2024-01-10 22:14:45 UTC+00:00

Running all new migrations...
        Running: (App) 2024-01-10-214032_App\Database\Migrations\CreateTestTable
Migrations complete.
dg@tvenkinys:~/Programavimas/MOK/ci4bugDemo$ php spark db:table invoices --metadata

CodeIgniter v4.4.4 Command Line Tool - Server Time: 2024-01-10 22:14:56 UTC+00:00

List of Metadata Information in Table "invoices":

+----------------+----------+------------+----------+---------+-------------+
| Field Name     | Type     | Max Length | Nullable | Default | Primary Key |
+----------------+----------+------------+----------+---------+-------------+
| id             | INTEGER  |            | Yes      |         | Yes         |
| user_id        | INT      |            | No       |         | No          |
| month          | VARCHAR  |            | No       |         | No          |
| invoice_series | VARCHAR  |            | No       |         | No          |
| total          | DECIMAL  |            | No       |         | No          |
| paid           | TINYINT  |            | No       | 0       | No          |
| paid_date      | VARCHAR  |            | Yes      | NULL    | No          |
| created_at     | DATETIME |            | No       |         | No          |
| updated_at     | DATETIME |            | No       |         | No          |
+----------------+----------+------------+----------+---------+-------------+

dg@tvenkinys:~/Programavimas/MOK/ci4bugDemo$ php public/index.php home
dg@tvenkinys:~/Programavimas/MOK/ci4bugDemo$ php spark db:table invoices --metadata

CodeIgniter v4.4.4 Command Line Tool - Server Time: 2024-01-10 22:15:25 UTC+00:00

List of Metadata Information in Table "invoices":

+------------+----------+------------+----------+---------+-------------+
| Field Name | Type     | Max Length | Nullable | Default | Primary Key |
+------------+----------+------------+----------+---------+-------------+
| id         | INTEGER  |            | Yes      | NULL    | Yes         |
| user_id    | INT      |            | Yes      | NULL    | No          |
| month      | VARCHAR  |            | Yes      | NULL    | No          |
| series     | VARCHAR  |            | No       | ''      | No          |
| total      | DECIMAL  |            | Yes      | NULL    | No          |
| paid       | TINYINT  |            | No       | '0'     | No          |
| paid_date  | VARCHAR  |            | Yes      | 'NULL'  | No          |
| created_at | DATETIME |            | Yes      | NULL    | No          |
| updated_at | DATETIME |            | Yes      | NULL    | No          |
+------------+----------+------------+----------+---------+-------------+

Note that the only table field that had to change (and only in it's name) was invoice_series -> series, and not the massive changes in Nullable and Default columns.

Another strange thing: if I shorten the test code to this, omitting the array items for everything but the table column name:

$fields = [
        'invoice_series' => [
            'name'       => 'series',
        ],
    ];

The table name does not get changed (and nothing is corrupted). But then I add

'type' => 'VARCHAR',

and boom, all the damage is done after running the code.

Expected Output

I expect only the table column name to change.

Anything else?

I have not tested the other DB's, but I expect this to be an issue only in SQLite3 case (though someone might run my code on mysql to be sure).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugVerified issues on the current code behavior or pull requests that will fix themdatabaseIssues or pull requests that affect the database layer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions