@@ -358,11 +358,17 @@ bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer *layer, const
358
358
359
359
QgsFeature QgsVectorLayerUtils::createFeature ( const QgsVectorLayer *layer, const QgsGeometry &geometry,
360
360
const QgsAttributeMap &attributes, QgsExpressionContext *context )
361
+ {
362
+ return createFeatures ( layer, QgsFeaturesDataList () << QgsFeaturesData ( geometry, attributes ), context ).first ();
363
+ }
364
+
365
+ QgsFeatureList QgsVectorLayerUtils::createFeatures ( const QgsVectorLayer *layer, const QgsFeaturesDataList &featuresData, QgsExpressionContext *context )
361
366
{
362
367
if ( !layer )
363
- {
364
- return QgsFeature ();
365
- }
368
+ return QgsFeatureList ();
369
+
370
+ QgsFeatureList result;
371
+ result.reserve ( featuresData.length () );
366
372
367
373
QgsExpressionContext *evalContext = context;
368
374
std::unique_ptr< QgsExpressionContext > tempContext;
@@ -375,94 +381,104 @@ QgsFeature QgsVectorLayerUtils::createFeature( const QgsVectorLayer *layer, cons
375
381
376
382
QgsFields fields = layer->fields ();
377
383
378
- QgsFeature newFeature ( fields );
379
- newFeature.setValid ( true );
380
- newFeature.setGeometry ( geometry );
384
+ // Cache unique values
385
+ QMap<int , QSet<QVariant>> uniqueValueCaches;
381
386
382
- // initialize attributes
383
- newFeature.initAttributes ( fields.count () );
384
- for ( int idx = 0 ; idx < fields.count (); ++idx )
387
+ for ( const auto &fd : qgis::as_const ( featuresData ) )
385
388
{
386
- QVariant v;
387
- bool checkUnique = true ;
388
389
389
- // in order of priority:
390
- // 1. passed attribute value and if field does not have a unique constraint like primary key
391
- if ( attributes.contains ( idx ) )
390
+ QgsFeature newFeature ( fields );
391
+ newFeature.setValid ( true );
392
+ newFeature.setGeometry ( fd.geometry () );
393
+
394
+ // initialize attributes
395
+ newFeature.initAttributes ( fields.count () );
396
+ for ( int idx = 0 ; idx < fields.count (); ++idx )
392
397
{
393
- v = attributes.value ( idx );
394
- }
398
+ QVariant v;
399
+ bool checkUnique = true ;
400
+ const bool hasUniqueConstraint { static_cast <bool >( fields.at ( idx ).constraints ().constraints () & QgsFieldConstraints::ConstraintUnique ) };
395
401
396
- // Cache unique values
397
- QSet<QVariant> uniqueValues { layer->uniqueValues ( idx ) };
402
+ // in order of priority:
403
+ // 1. passed attribute value and if field does not have a unique constraint like primary key
404
+ if ( fd.attributes ().contains ( idx ) )
405
+ {
406
+ v = fd.attributes ().value ( idx );
407
+ }
398
408
399
- // 2. client side default expression
400
- // note - deliberately not using else if!
401
- if ( ( !v.isValid () || ( fields.at ( idx ).constraints ().constraints () & QgsFieldConstraints::ConstraintUnique
402
- && uniqueValues.contains ( v ) ) )
403
- && layer->defaultValueDefinition ( idx ).isValid () )
404
- {
405
- // client side default expression set - takes precedence over all. Why? Well, this is the only default
406
- // which QGIS users have control over, so we assume that they're deliberately overriding any
407
- // provider defaults for some good reason and we should respect that
408
- v = layer->defaultValue ( idx, newFeature, evalContext );
409
- }
409
+ // Cache unique values
410
+ if ( hasUniqueConstraint && ! uniqueValueCaches.contains ( idx ) )
411
+ uniqueValueCaches[ idx ] = layer->uniqueValues ( idx );
410
412
411
- // 3. provider side default value clause
412
- // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
413
- if ( ( !v.isValid () || ( fields.at ( idx ).constraints ().constraints () & QgsFieldConstraints::ConstraintUnique
414
- && uniqueValues.contains ( v ) ) )
415
- && fields.fieldOrigin ( idx ) == QgsFields::OriginProvider )
416
- {
417
- int providerIndex = fields.fieldOriginIndex ( idx );
418
- QString providerDefault = layer->dataProvider ()->defaultValueClause ( providerIndex );
419
- if ( !providerDefault.isEmpty () )
413
+ // 2. client side default expression
414
+ // note - deliberately not using else if!
415
+ if ( ( !v.isValid () || ( hasUniqueConstraint
416
+ && uniqueValueCaches[ idx ].contains ( v ) ) )
417
+ && layer->defaultValueDefinition ( idx ).isValid () )
420
418
{
421
- v = providerDefault;
422
- checkUnique = false ;
419
+ // client side default expression set - takes precedence over all. Why? Well, this is the only default
420
+ // which QGIS users have control over, so we assume that they're deliberately overriding any
421
+ // provider defaults for some good reason and we should respect that
422
+ v = layer->defaultValue ( idx, newFeature, evalContext );
423
423
}
424
- }
425
424
426
- // 4. provider side default literal
427
- // note - deliberately not using else if!
428
- if ( ( !v.isValid () || ( checkUnique && fields.at ( idx ).constraints ().constraints () & QgsFieldConstraints::ConstraintUnique
429
- && uniqueValues.contains ( v ) ) )
430
- && fields.fieldOrigin ( idx ) == QgsFields::OriginProvider )
431
- {
432
- int providerIndex = fields.fieldOriginIndex ( idx );
433
- v = layer->dataProvider ()->defaultValue ( providerIndex );
434
- if ( v.isValid () )
425
+ // 3. provider side default value clause
426
+ // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
427
+ if ( ( !v.isValid () || ( hasUniqueConstraint
428
+ && uniqueValueCaches[ idx ].contains ( v ) ) )
429
+ && fields.fieldOrigin ( idx ) == QgsFields::OriginProvider )
435
430
{
436
- // trust that the provider default has been sensibly set not to violate any constraints
437
- checkUnique = false ;
431
+ int providerIndex = fields.fieldOriginIndex ( idx );
432
+ QString providerDefault = layer->dataProvider ()->defaultValueClause ( providerIndex );
433
+ if ( !providerDefault.isEmpty () )
434
+ {
435
+ v = providerDefault;
436
+ checkUnique = false ;
437
+ }
438
438
}
439
- }
440
439
441
- // 5. passed attribute value
442
- // note - deliberately not using else if!
443
- if ( !v.isValid () && attributes.contains ( idx ) )
444
- {
445
- v = attributes.value ( idx );
446
- }
440
+ // 4. provider side default literal
441
+ // note - deliberately not using else if!
442
+ if ( ( !v.isValid () || ( checkUnique && hasUniqueConstraint
443
+ && uniqueValueCaches[ idx ].contains ( v ) ) )
444
+ && fields.fieldOrigin ( idx ) == QgsFields::OriginProvider )
445
+ {
446
+ int providerIndex = fields.fieldOriginIndex ( idx );
447
+ v = layer->dataProvider ()->defaultValue ( providerIndex );
448
+ if ( v.isValid () )
449
+ {
450
+ // trust that the provider default has been sensibly set not to violate any constraints
451
+ checkUnique = false ;
452
+ }
453
+ }
447
454
448
- // last of all... check that unique constraints are respected
449
- // we can't handle not null or expression constraints here, since there's no way to pick a sensible
450
- // value if the constraint is violated
451
- if ( checkUnique && fields.at ( idx ).constraints ().constraints () & QgsFieldConstraints::ConstraintUnique )
452
- {
453
- if ( uniqueValues.contains ( v ) )
455
+ // 5. passed attribute value
456
+ // note - deliberately not using else if!
457
+ if ( !v.isValid () && fd.attributes ().contains ( idx ) )
454
458
{
455
- // unique constraint violated
456
- QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValue ( layer, idx, v );
457
- if ( uniqueValue.isValid () )
458
- v = uniqueValue;
459
+ v = fd.attributes ().value ( idx );
459
460
}
460
- }
461
461
462
- newFeature.setAttribute ( idx, v );
462
+ // last of all... check that unique constraints are respected
463
+ // we can't handle not null or expression constraints here, since there's no way to pick a sensible
464
+ // value if the constraint is violated
465
+ if ( checkUnique && hasUniqueConstraint )
466
+ {
467
+ if ( uniqueValueCaches[ idx ].contains ( v ) )
468
+ {
469
+ // unique constraint violated
470
+ QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValue ( layer, idx, v );
471
+ if ( uniqueValue.isValid () )
472
+ v = uniqueValue;
473
+ }
474
+ }
475
+ if ( hasUniqueConstraint )
476
+ uniqueValueCaches[ idx ].insert ( v );
477
+ newFeature.setAttribute ( idx, v );
478
+ }
479
+ result.append ( newFeature );
463
480
}
464
-
465
- return newFeature;
481
+ return result;
466
482
}
467
483
468
484
QgsFeature QgsVectorLayerUtils::duplicateFeature ( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext )
@@ -772,3 +788,18 @@ QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureC
772
788
return mDuplicatedFeatures;
773
789
}
774
790
*/
791
+
792
+ QgsVectorLayerUtils::QgsFeaturesData::QgsFeaturesData ( const QgsGeometry &geometry, const QgsAttributeMap &attributes ):
793
+ mGeometry( geometry ),
794
+ mAttributes( attributes )
795
+ {}
796
+
797
+ QgsGeometry QgsVectorLayerUtils::QgsFeaturesData::geometry () const
798
+ {
799
+ return mGeometry ;
800
+ }
801
+
802
+ QgsAttributeMap QgsVectorLayerUtils::QgsFeaturesData::attributes () const
803
+ {
804
+ return mAttributes ;
805
+ }
0 commit comments