@@ -177,11 +177,48 @@ impl Dataset {
177
177
}
178
178
Ok ( Transaction :: new ( self ) )
179
179
}
180
+
181
+ /// Optionally start a transaction before running `func` for performance
182
+ ///
183
+ /// This uses transaction if the dataset supports it, otherwise it
184
+ /// runs the `func` function as it is on the dataset. If the
185
+ /// closure results in error, and it is a transaction, it is
186
+ /// rolled back. If there is error in rollback it is ignored.
187
+ pub fn maybe_batch ( & mut self , func : impl Fn ( & Dataset ) -> Result < ( ) > ) -> Result < ( ) > {
188
+ let force = 0 ; // since this is for speed
189
+ let rv = unsafe { gdal_sys:: GDALDatasetStartTransaction ( self . c_dataset ( ) , force) } ;
190
+ if rv == OGRErr :: OGRERR_UNSUPPORTED_OPERATION {
191
+ func ( self )
192
+ } else if rv == OGRErr :: OGRERR_NONE {
193
+ let res = func ( self ) ;
194
+ if res. is_ok ( ) {
195
+ let rv = unsafe { gdal_sys:: GDALDatasetCommitTransaction ( self . c_dataset ( ) ) } ;
196
+ if rv != OGRErr :: OGRERR_NONE {
197
+ Err ( GdalError :: OgrError {
198
+ err : rv,
199
+ method_name : "GDALDatasetCommitTransaction" ,
200
+ } )
201
+ } else {
202
+ res
203
+ }
204
+ } else {
205
+ let _ = unsafe { gdal_sys:: GDALDatasetRollbackTransaction ( self . c_dataset ( ) ) } ;
206
+ // ignoring rollback error
207
+ res
208
+ }
209
+ } else {
210
+ // transaction supported but failed
211
+ Err ( GdalError :: OgrError {
212
+ err : rv,
213
+ method_name : "GDALDatasetStartTransaction" ,
214
+ } )
215
+ }
216
+ }
180
217
}
181
218
182
219
#[ cfg( test) ]
183
220
mod tests {
184
- use crate :: test_utils:: { fixture, open_gpkg_for_update} ;
221
+ use crate :: test_utils:: { fixture, open_dataset_for_update , open_gpkg_for_update} ;
185
222
use crate :: vector:: { Geometry , LayerAccess } ;
186
223
use crate :: Dataset ;
187
224
@@ -241,4 +278,30 @@ mod tests {
241
278
let mut ds = Dataset :: open ( fixture ( "roads.geojson" ) ) . unwrap ( ) ;
242
279
assert ! ( ds. start_transaction( ) . is_err( ) ) ;
243
280
}
281
+
282
+ #[ test]
283
+ fn test_maybe_batch ( ) {
284
+ let ( _temp_path, mut ds) = open_gpkg_for_update ( & fixture ( "poly.gpkg" ) ) ;
285
+ let orig_feature_count = ds. layer ( 0 ) . unwrap ( ) . feature_count ( ) ;
286
+
287
+ let res = ds. maybe_batch ( |d| {
288
+ let mut layer = d. layer ( 0 ) . unwrap ( ) ;
289
+ layer. create_feature ( polygon ( ) )
290
+ } ) ;
291
+ assert ! ( res. is_ok( ) ) ;
292
+ assert_eq ! ( ds. layer( 0 ) . unwrap( ) . feature_count( ) , orig_feature_count + 1 ) ;
293
+ }
294
+
295
+ #[ test]
296
+ fn test_maybe_transaction_unsupported ( ) {
297
+ let ( _temp_path, mut ds) = open_dataset_for_update ( & fixture ( "roads.geojson" ) ) ;
298
+ let orig_feature_count = ds. layer ( 0 ) . unwrap ( ) . feature_count ( ) ;
299
+
300
+ let res = ds. maybe_batch ( |d| {
301
+ let mut layer = d. layer ( 0 ) . unwrap ( ) ;
302
+ layer. create_feature ( polygon ( ) )
303
+ } ) ;
304
+ assert ! ( res. is_ok( ) ) ;
305
+ assert_eq ! ( ds. layer( 0 ) . unwrap( ) . feature_count( ) , orig_feature_count + 1 ) ;
306
+ }
244
307
}
0 commit comments