typeorm / typeorm

ORM for TypeScript and JavaScript. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.
http://typeorm.io
MIT License
34.22k stars 6.31k forks source link

queryRunner.query drops column when I try to modify a column #3147

Open its-vincesanity opened 5 years ago

its-vincesanity commented 5 years ago

Issue type:

[ ] question [x] bug report [ ] feature request [ ] documentation issue

Database system/driver:

[ ] cordova [ ] mongodb [ ] mssql [x] mysql / mariadb [ ] oracle [ ] postgres [ ] sqlite [ ] sqljs [ ] react-native [ ] expo

TypeORM version:

[x] latest [ ] @next [ ] 0.x.x (or put your version here)

I wanted to migrate a column type from VARCHAR(255) to TEXT with:

export class NoTypeToTextMigration1542892455634 implements MigrationInterface {
  async up(queryRunner: QueryRunner): Promise<any> {
    // audit_log
    await queryRunner.query('ALTER TABLE `audit_log` MODIFY COLUMN `body` TEXT');
  }

Sometimes it works as expected and sometimes it drops the data from my column. So, I setup an audit log in my MySQL:

SET GLOBAL log_output = 'TABLE';
SET GLOBAL general_log = 'ON';

My logs say:

| 2018-11-22 13:16:08 | root[root] @  [172.17.0.1] |        22 |         0 | Query        | ALTER TABLE `audit_log` DROP COLUMN `body`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| 2018-11-22 13:16:08 | root[root] @  [172.17.0.1] |        22 |         0 | Query        | ALTER TABLE `audit_log` ADD `body` text NOT NULL

Why did it drop my table, I don't want lose my data If I change a column type :\

its-vincesanity commented 5 years ago

Same results with:

await queryRunner.renameColumn('audit_log', 'body', new TableColumn( {
  name: 'body',
  type: 'text',
  isNullable: true
}));

and

await queryRunner.changeColumn('audit_log', 'body', new TableColumn( {
  name: 'body',
  type: 'text',
  isNullable: true
}));

Both call

ALTER TABLE `audit_log` DROP COLUMN `body`
jyang0110 commented 5 years ago

Is there any explanation about why data is lost?

Kononnable commented 5 years ago

@vincevaghalsen Migrations just execute passed query, so those alter table statements are generated from somewhere else. Are you sure you don't have synchronize: true set at the same time?

As for renameColumn and changeColumn: renameColumn was suposed to be data-safe, but it isn't if you pass TableColumn instead of a string. Tbh. I have no idea why there is a possibility of passing a TableColumn object here. Method name is rename column so only rename should be possible.

@pleerock @AlexMesser Can we change newTableColumnOrName: TableColumn|string to newColumnName: string? We have a major naming problem here. Current behavior is not data-safe while renameColumn was meant to be data-safe.

ronielramos commented 4 years ago

I make some tests, i have the same problem, so, i expect to be helpful:

version: mysql 5.6.44

On generate migration for alter a column, the migrations always generate a drop and create instead a change.

https://github.com/typeorm/typeorm/blob/3227c0b7b9f79868f755eb40e72287bdb60d71b6/src/driver/mysql/MysqlQueryRunner.ts#L559-L564

This comparison returns true, even without significant changes, so the drop is created.