@@ -820,6 +820,77 @@ mod test {
820820 Ok ( ( ) )
821821 }
822822
823+ // When using RETURNING clauses, DuckDB core treats the statement as a query result instead of a modification
824+ // statement. This causes execute() to return 0 changed rows and insert() to fail with an error.
825+ // This test demonstrates current behavior and proper usage patterns for RETURNING clauses.
826+ #[ test]
827+ fn test_insert_with_returning_clause ( ) -> Result < ( ) > {
828+ let db = Connection :: open_in_memory ( ) ?;
829+ db. execute_batch (
830+ "CREATE SEQUENCE location_id_seq START WITH 1 INCREMENT BY 1;
831+ CREATE TABLE location (
832+ id INTEGER PRIMARY KEY DEFAULT nextval('location_id_seq'),
833+ name TEXT NOT NULL
834+ )" ,
835+ ) ?;
836+
837+ // INSERT without RETURNING using execute
838+ let changes = db. execute ( "INSERT INTO location (name) VALUES (?)" , [ "test1" ] ) ?;
839+ assert_eq ! ( changes, 1 ) ;
840+
841+ // INSERT with RETURNING using execute - returns 0 (known limitation)
842+ let changes = db. execute ( "INSERT INTO location (name) VALUES (?) RETURNING id" , [ "test2" ] ) ?;
843+ assert_eq ! ( changes, 0 ) ;
844+
845+ // Verify the row was actually inserted despite returning 0
846+ let count: i64 = db. query_row ( "SELECT COUNT(*) FROM location" , [ ] , |r| r. get ( 0 ) ) ?;
847+ assert_eq ! ( count, 2 ) ;
848+
849+ // INSERT without RETURNING using insert
850+ let mut stmt = db. prepare ( "INSERT INTO location (name) VALUES (?)" ) ?;
851+ stmt. insert ( [ "test3" ] ) ?;
852+
853+ // INSERT with RETURNING using insert - fails (known limitation)
854+ let mut stmt = db. prepare ( "INSERT INTO location (name) VALUES (?) RETURNING id" ) ?;
855+ let result = stmt. insert ( [ "test4" ] ) ;
856+ assert ! ( matches!( result, Err ( Error :: StatementChangedRows ( 0 ) ) ) ) ;
857+
858+ // Verify the row was still inserted despite the error
859+ let count: i64 = db. query_row ( "SELECT COUNT(*) FROM location" , [ ] , |r| r. get ( 0 ) ) ?;
860+ assert_eq ! ( count, 4 ) ;
861+
862+ // Proper way to use RETURNING - with query_row
863+ let id: i64 = db. query_row ( "INSERT INTO location (name) VALUES (?) RETURNING id" , [ "test5" ] , |r| {
864+ r. get ( 0 )
865+ } ) ?;
866+ assert_eq ! ( id, 5 ) ;
867+
868+ // Proper way to use RETURNING - with query_map
869+ let mut stmt = db. prepare ( "INSERT INTO location (name) VALUES (?) RETURNING id" ) ?;
870+ let ids: Vec < i64 > = stmt
871+ . query_map ( [ "test6" ] , |row| row. get ( 0 ) ) ?
872+ . collect :: < Result < Vec < _ > > > ( ) ?;
873+ assert_eq ! ( ids. len( ) , 1 ) ;
874+ assert_eq ! ( ids[ 0 ] , 6 ) ;
875+
876+ // Proper way to use RETURNING - with query_one
877+ let id: i64 = db
878+ . prepare ( "INSERT INTO location (name) VALUES (?) RETURNING id" ) ?
879+ . query_one ( [ "test7" ] , |r| r. get ( 0 ) ) ?;
880+ assert_eq ! ( id, 7 ) ;
881+
882+ // Multiple RETURNING columns
883+ let ( id, name) : ( i64 , String ) = db. query_row (
884+ "INSERT INTO location (name) VALUES (?) RETURNING id, name" ,
885+ [ "test8" ] ,
886+ |r| Ok ( ( r. get ( 0 ) ?, r. get ( 1 ) ?) ) ,
887+ ) ?;
888+ assert_eq ! ( id, 8 ) ;
889+ assert_eq ! ( name, "test8" ) ;
890+
891+ Ok ( ( ) )
892+ }
893+
823894 #[ test]
824895 fn test_exists ( ) -> Result < ( ) > {
825896 let db = Connection :: open_in_memory ( ) ?;
0 commit comments