@@ -82,3 +82,81 @@ async fn auto_increment(conn: ConnectionAsync) {
8282 assert ! ( matches!( pk_val2, SqlVal :: Int ( _) ) , "Second PK should be Int" ) ;
8383 assert_ne ! ( pk_val, pk_val2, "PKs should be different" ) ;
8484}
85+
86+ /// Test that `insert_or_replace` correctly quotes reserved word primary keys in ON CONFLICT clause.
87+ #[ butane_test( nomigrate) ]
88+ async fn reserved_word ( conn : ConnectionAsync ) {
89+ // Create table with "order" as primary key (a reserved SQL keyword)
90+ let pkcol = Column :: new ( "order" , SqlType :: BigInt ) ;
91+ let bar_column = Column :: new ( "bar" , SqlType :: Text ) ;
92+
93+ let mut table = ATable :: new ( "reserved_pkey_test" . to_string ( ) ) ;
94+
95+ // Create "order" column as primary key with auto-increment
96+ let order_col = AColumn :: new (
97+ pkcol. name ( ) ,
98+ DeferredSqlType :: KnownId ( TypeIdentifier :: Ty ( SqlType :: BigInt ) ) ,
99+ false , // not nullable
100+ true , // is primary key
101+ true , // auto-increment (this is what we're testing!)
102+ false , // not unique (pk already implies unique)
103+ None , // no default
104+ None , // no foreign key
105+ ) ;
106+ table. add_column ( order_col) ;
107+
108+ // Create bar column
109+ let bar_col = AColumn :: new (
110+ bar_column. name ( ) ,
111+ DeferredSqlType :: KnownId ( TypeIdentifier :: Ty ( SqlType :: Text ) ) ,
112+ false , // not nullable
113+ false , // not pk
114+ false , // not auto
115+ false , // not unique
116+ None , // no default
117+ None , // no foreign key
118+ ) ;
119+ table. add_column ( bar_col) ;
120+
121+ // Generate and execute CREATE TABLE
122+ let backend = conn. backend ( ) ;
123+ let adb = ADB :: default ( ) ;
124+ let create_sql = backend
125+ . create_migration_sql ( & adb, vec ! [ Operation :: AddTable ( table) ] )
126+ . unwrap ( ) ;
127+
128+ conn. execute ( & create_sql) . await . unwrap ( ) ;
129+
130+ // Now test insert_or_replace which should properly quote the "order" column in the ON CONFLICT clause
131+ let columns = [ pkcol. clone ( ) , bar_column. clone ( ) ] ;
132+ let values = [ SqlValRef :: BigInt ( 1 ) , SqlValRef :: Text ( "first" ) ] ;
133+
134+ // First insert
135+ conn. insert_or_replace ( "reserved_pkey_test" , & columns, & pkcol, & values)
136+ . await
137+ . unwrap ( ) ;
138+
139+ // Second insert with same pk should update
140+ let values2 = [ SqlValRef :: BigInt ( 1 ) , SqlValRef :: Text ( "updated" ) ] ;
141+ conn. insert_or_replace ( "reserved_pkey_test" , & columns, & pkcol, & values2)
142+ . await
143+ . unwrap ( ) ;
144+
145+ // Verify only one row exists after the upsert.
146+ // TODO: There is a bug in turso that fails when using COUNT(anything) on this table.
147+ let query_columns = [ pkcol. clone ( ) , bar_column. clone ( ) ] ;
148+ let mut result = conn
149+ . query ( "reserved_pkey_test" , & query_columns, None , None , None , None )
150+ . await
151+ . unwrap ( ) ;
152+
153+ let mut count = 0 ;
154+ while result. next ( ) . unwrap ( ) . is_some ( ) {
155+ count += 1 ;
156+ }
157+ assert_eq ! (
158+ count, 1 ,
159+ "Expected exactly 1 row after upsert, found {}" ,
160+ count
161+ ) ;
162+ }
0 commit comments