@@ -625,5 +625,90 @@ void main() {
625625 expect (TableMutationEngine .normalizeIdentifier ('`USER_ID`' ), 'user_id' );
626626 expect (TableMutationEngine .normalizeIdentifier ('user_id' ), 'user_id' );
627627 });
628+
629+ test ('preserves literal string NULL in WHERE clause for text primary key' , () {
630+ final plan = TableMutationEngine .generatePlan (
631+ dialect: SqlDialect .postgres,
632+ tableName: 'codes' ,
633+ columns: ['code' , 'description' ],
634+ primaryKeys: ['code' ],
635+ originalRows: [
636+ ['NULL' , 'Special null code' ],
637+ ],
638+ modifiedCells: {
639+ 0 : {1 : 'Updated description' },
640+ },
641+ insertedRows: const [],
642+ deletedRowIndices: const {},
643+ columnMeta: {
644+ 'code' : const TableColumnMeta (name: 'code' , dataType: 'varchar' ),
645+ 'description' : const TableColumnMeta (name: 'description' , dataType: 'text' ),
646+ },
647+ );
648+
649+ expect (plan.statementCount, 1 );
650+ final stmt = plan.statements.first;
651+ expect (stmt.type, MutationType .update);
652+ expect (
653+ stmt.sql,
654+ "UPDATE \" codes\" SET \" description\" = 'Updated description' WHERE \" code\" = 'NULL'" ,
655+ );
656+ });
657+
658+ test ('uses IS NULL in WHERE clause when value is kNullSentinel in text column' , () {
659+ final plan = TableMutationEngine .generatePlan (
660+ dialect: SqlDialect .postgres,
661+ tableName: 'codes' ,
662+ columns: ['code' , 'description' ],
663+ primaryKeys: ['code' ],
664+ originalRows: [
665+ [TableMutationEngine .kNullSentinel, 'Special null code' ],
666+ ],
667+ modifiedCells: {
668+ 0 : {1 : 'Updated description' },
669+ },
670+ insertedRows: const [],
671+ deletedRowIndices: const {},
672+ columnMeta: {
673+ 'code' : const TableColumnMeta (name: 'code' , dataType: 'varchar' ),
674+ 'description' : const TableColumnMeta (name: 'description' , dataType: 'text' ),
675+ },
676+ );
677+
678+ expect (plan.statementCount, 1 );
679+ final stmt = plan.statements.first;
680+ expect (stmt.type, MutationType .update);
681+ expect (
682+ stmt.sql,
683+ "UPDATE \" codes\" SET \" description\" = 'Updated description' WHERE \" code\" IS NULL" ,
684+ );
685+ });
686+
687+ test ('preserves literal string NULL in unkeyed row match-all WHERE clause for text columns' , () {
688+ final plan = TableMutationEngine .generatePlan (
689+ dialect: SqlDialect .mysql,
690+ tableName: 'logs' ,
691+ columns: ['tag' , 'status' ],
692+ primaryKeys: const [],
693+ originalRows: [
694+ ['NULL' , 'null' ],
695+ ],
696+ modifiedCells: const {},
697+ insertedRows: const [],
698+ deletedRowIndices: {0 },
699+ columnMeta: {
700+ 'tag' : const TableColumnMeta (name: 'tag' , dataType: 'varchar(50)' ),
701+ 'status' : const TableColumnMeta (name: 'status' , dataType: 'text' ),
702+ },
703+ );
704+
705+ expect (plan.statementCount, 1 );
706+ final stmt = plan.statements.first;
707+ expect (stmt.type, MutationType .delete);
708+ expect (
709+ stmt.sql,
710+ "DELETE FROM `logs` WHERE `tag` = 'NULL' AND `status` = 'null'" ,
711+ );
712+ });
628713 });
629714}
0 commit comments