@@ -1670,6 +1670,16 @@ fn release_savepoint(trx_id: &str, name: &str) -> NifResult<Atom> {
16701670 . get_mut ( trx_id)
16711671 . ok_or_else ( || rustler:: Error :: Term ( Box :: new ( "Transaction not found" ) ) ) ?;
16721672
1673+ // Validate savepoint name is a valid SQL identifier (alphanumeric + underscore, not starting with digit)
1674+ if name. is_empty ( )
1675+ || !name. chars ( ) . all ( |c| c. is_alphanumeric ( ) || c == '_' )
1676+ || name. chars ( ) . next ( ) . map_or ( true , |c| c. is_ascii_digit ( ) )
1677+ {
1678+ return Err ( rustler:: Error :: Term ( Box :: new (
1679+ "Invalid savepoint name: must be a valid SQL identifier" ,
1680+ ) ) ) ;
1681+ }
1682+
16731683 let sql = format ! ( "RELEASE SAVEPOINT {}" , name) ;
16741684
16751685 TOKIO_RUNTIME
@@ -1689,6 +1699,16 @@ fn rollback_to_savepoint(trx_id: &str, name: &str) -> NifResult<Atom> {
16891699 . get_mut ( trx_id)
16901700 . ok_or_else ( || rustler:: Error :: Term ( Box :: new ( "Transaction not found" ) ) ) ?;
16911701
1702+ // Validate savepoint name is a valid SQL identifier (alphanumeric + underscore, not starting with digit)
1703+ if name. is_empty ( )
1704+ || !name. chars ( ) . all ( |c| c. is_alphanumeric ( ) || c == '_' )
1705+ || name. chars ( ) . next ( ) . map_or ( true , |c| c. is_ascii_digit ( ) )
1706+ {
1707+ return Err ( rustler:: Error :: Term ( Box :: new (
1708+ "Invalid savepoint name: must be a valid SQL identifier" ,
1709+ ) ) ) ;
1710+ }
1711+
16921712 let sql = format ! ( "ROLLBACK TO SAVEPOINT {}" , name) ;
16931713
16941714 TOKIO_RUNTIME
@@ -1701,8 +1721,8 @@ fn rollback_to_savepoint(trx_id: &str, name: &str) -> NifResult<Atom> {
17011721}
17021722
17031723/// Get the current frame number from a remote replica database.
1704- /// Returns 0 if not a replica or frame number unknown .
1705- /// Note: libsql 0.9.27 doesn't expose frame number API yet
1724+ /// **Note**: This is currently a placeholder - libsql 0.9.27 doesn't expose the frame number API .
1725+ /// Always returns 0. Will be implemented when the upstream API becomes available.
17061726#[ rustler:: nif( schedule = "DirtyIo" ) ]
17071727fn get_frame_number ( conn_id : & str ) -> NifResult < u64 > {
17081728 let conn_map = safe_lock ( & CONNECTION_REGISTRY , "get_frame_number conn_map" ) ?;
0 commit comments