30 #include <QRegularExpression>
35 #define TEXT_PROVIDER_KEY QStringLiteral( "memory" )
36 #define TEXT_PROVIDER_DESCRIPTION QStringLiteral( "Memory provider" )
38 QgsMemoryProvider::QgsMemoryProvider(
const QString &uri,
const ProviderOptions &options, QgsDataProvider::ReadFlags flags )
43 const QUrl url = QUrl::fromEncoded( uri.toUtf8() );
44 const QUrlQuery query( url );
46 if ( query.hasQueryItem( QStringLiteral(
"geometry" ) ) )
48 geometry = query.queryItemValue( QStringLiteral(
"geometry" ) );
52 geometry = url.path();
55 if ( geometry.compare( QLatin1String(
"none" ), Qt::CaseInsensitive ) == 0 )
64 if ( query.hasQueryItem( QStringLiteral(
"crs" ) ) )
66 const QString crsDef = query.queryItemValue( QStringLiteral(
"crs" ) );
67 mCrs.createFromString( crsDef );
78 setNativeTypes( QList< NativeType >()
124 if ( query.hasQueryItem( QStringLiteral(
"field" ) ) )
126 QList<QgsField> attributes;
127 const thread_local QRegularExpression reFieldDef(
"\\:"
133 QRegularExpression::CaseInsensitiveOption );
134 const QStringList fields = query.allQueryItemValues( QStringLiteral(
"field" ) );
135 for (
int i = 0; i < fields.size(); i++ )
137 QString name = QUrl::fromPercentEncoding( fields.at( i ).toUtf8() );
138 const QRegularExpressionMatch regularExpressionMatch = reFieldDef.match( name );
141 QVariant::Type type = QVariant::String;
142 QVariant::Type subType = QVariant::Invalid;
143 QString
typeName( QStringLiteral(
"string" ) );
147 if ( regularExpressionMatch.hasMatch() )
149 name = name.mid( 0, regularExpressionMatch.capturedStart() );
150 typeName = regularExpressionMatch.captured( 1 ).toLower();
153 bool isNativeType =
false;
154 const QList<QgsVectorDataProvider::NativeType> nativeTypesList( nativeTypes() );
155 for (
const NativeType &nativeType : nativeTypesList )
157 if ( nativeType.mTypeName.toLower() ==
typeName )
160 type = nativeType.mType;
161 subType = nativeType.mSubType;
168 if ( isNativeType ==
false )
170 if (
typeName == QLatin1String(
"int" ) )
172 type = QVariant::Int;
173 typeName = QStringLiteral(
"integer" );
175 else if (
typeName == QLatin1String(
"long" ) )
177 type = QVariant::LongLong;
178 typeName = QStringLiteral(
"int8" );
180 else if (
typeName == QLatin1String(
"bool" ) )
182 type = QVariant::Bool;
183 typeName = QStringLiteral(
"boolean" );
188 type = QVariant::String;
189 typeName = QStringLiteral(
"string" );
194 if (
typeName == QLatin1String(
"real" ) ||
typeName == QLatin1String(
"double" ) )
200 if ( !regularExpressionMatch.captured( 2 ).isEmpty() )
201 length = regularExpressionMatch.captured( 2 ).toInt();
203 if ( !regularExpressionMatch.captured( 3 ).isEmpty() )
204 precision = regularExpressionMatch.captured( 3 ).toInt();
207 if ( !regularExpressionMatch.captured( 4 ).isEmpty() )
209 if ( subType == QVariant::Invalid )
212 if ( type != QVariant::List && type != QVariant::StringList )
213 type = type == QVariant::String ? QVariant::StringList : QVariant::List;
215 const QLatin1String listSuffix(
"list" );
216 if ( !
typeName.endsWith( listSuffix ) )
217 typeName += QLatin1String(
"list" );
223 addAttributes( attributes );
226 if ( query.hasQueryItem( QStringLiteral(
"index" ) ) && query.queryItemValue( QStringLiteral(
"index" ) ) == QLatin1String(
"yes" ) )
228 createSpatialIndex();
233 QgsMemoryProvider::~QgsMemoryProvider()
235 delete mSpatialIndex;
238 QString QgsMemoryProvider::providerKey()
240 return TEXT_PROVIDER_KEY;
243 QString QgsMemoryProvider::providerDescription()
245 return TEXT_PROVIDER_DESCRIPTION;
250 return new QgsMemoryFeatureSource(
this );
253 QString QgsMemoryProvider::dataSourceUri(
bool expandAuthConfig )
const
255 Q_UNUSED( expandAuthConfig )
257 QUrl uri( QStringLiteral(
"memory" ) );
260 query.addQueryItem( QStringLiteral(
"geometry" ), geometry );
262 if ( mCrs.isValid() )
265 const QString authid = mCrs.authid();
266 if ( authid.startsWith( QLatin1String(
"EPSG:" ) ) )
274 query.addQueryItem( QStringLiteral(
"crs" ), crsDef );
278 query.addQueryItem( QStringLiteral(
"index" ), QStringLiteral(
"yes" ) );
282 for (
int i = 0; i < attrs.size(); i++ )
294 typeName = QStringLiteral(
"integer" );
297 case QVariant::LongLong:
298 typeName = QStringLiteral(
"long" );
301 case QVariant::Double:
302 typeName = QStringLiteral(
"double" );
305 case QVariant::String:
306 typeName = QStringLiteral(
"string" );
315 fieldDef.append( QStringLiteral(
":%2(%3,%4)%5" ).arg(
typeName ).arg(
field.
length() ).arg(
field.
precision() ).arg( isList ? QStringLiteral(
"[]" ) : QString() ) );
316 query.addQueryItem( QStringLiteral(
"field" ), fieldDef );
318 uri.setQuery( query );
320 return QString( uri.toEncoded() );
324 QString QgsMemoryProvider::storageType()
const
326 return QStringLiteral(
"Memory storage" );
331 return QgsFeatureIterator(
new QgsMemoryFeatureIterator(
new QgsMemoryFeatureSource(
this ),
true, request ) );
337 if ( mExtent.isEmpty() && !mFeatures.isEmpty() )
340 if ( mSubsetString.isEmpty() )
343 const auto constMFeatures = mFeatures;
344 for (
const QgsFeature &feat : constMFeatures )
346 if ( feat.hasGeometry() )
347 mExtent.combineExtentWith( feat.geometry().boundingBox() );
361 else if ( mFeatures.isEmpty() )
363 mExtent.setMinimal();
374 long long QgsMemoryProvider::featureCount()
const
376 if ( mSubsetString.isEmpty() )
377 return mFeatures.count();
390 QgsFields QgsMemoryProvider::fields()
const
395 bool QgsMemoryProvider::isValid()
const
408 if ( QgsMemoryProvider *other = qobject_cast< QgsMemoryProvider * >( source ) )
411 mFeatures = other->mFeatures;
412 mNextFeatureId = other->mNextFeatureId;
413 mExtent = other->mExtent;
418 bool QgsMemoryProvider::addFeatures(
QgsFeatureList &flist, Flags flags )
422 const bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
424 const int fieldCount = mFields.count();
427 const auto oldExtent { mExtent };
428 const auto oldNextFeatureId { mNextFeatureId };
431 for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end() && result ; ++it )
433 it->setId( mNextFeatureId );
434 it->setValid(
true );
435 if ( it->attributes().count() < fieldCount )
440 for (
int i = it->attributes().count(); i < mFields.count(); ++i )
442 attributes.append( QVariant( mFields.at( i ).type() ) );
444 it->setAttributes( attributes );
446 else if ( it->attributes().count() > fieldCount )
449 pushError( tr(
"Feature has too many attributes (expecting %1, received %2)" ).arg( fieldCount ).arg( it->attributes().count() ) );
451 attributes.resize( mFields.count() );
452 it->setAttributes( attributes );
462 pushError( tr(
"Could not add feature with geometry type %1 to layer of type %2" ).arg(
QgsWkbTypes::displayString( it->geometry().wkbType() ),
469 bool conversionError {
false };
470 QString errorMessage;
471 for (
int i = 0; i < mFields.count(); ++i )
473 const QVariant originalValue = it->attribute( i );
474 QVariant attrValue = originalValue;
475 if ( ! attrValue.isNull() && ! mFields.at( i ).convertCompatible( attrValue, &errorMessage ) )
480 pushError( tr(
"Could not store attribute \"%1\": %2" )
481 .arg( mFields.at( i ).name(), errorMessage ) );
484 conversionError =
true;
487 else if ( attrValue.type() != originalValue.type() )
490 it->setAttribute( i, attrValue );
495 if ( conversionError )
497 if ( flags.testFlag( QgsFeatureSink::Flag::RollBackOnErrors ) )
504 mFeatures.insert( mNextFeatureId, *it );
505 addedFids.insert( mNextFeatureId );
507 if ( it->hasGeometry() )
510 mExtent.combineExtentWith( it->geometry().boundingBox() );
514 mSpatialIndex->addFeature( *it );
521 if ( ! result && flags.testFlag( QgsFeatureSink::Flag::RollBackOnErrors ) )
525 mFeatures.remove( addedFid );
528 mNextFeatureId = oldNextFeatureId;
538 bool QgsMemoryProvider::deleteFeatures(
const QgsFeatureIds &
id )
540 for ( QgsFeatureIds::const_iterator it =
id.begin(); it !=
id.end(); ++it )
542 const QgsFeatureMap::iterator fit = mFeatures.find( *it );
545 if ( fit == mFeatures.end() )
550 mSpatialIndex->deleteFeature( *fit );
552 mFeatures.erase( fit );
561 bool QgsMemoryProvider::addAttributes(
const QList<QgsField> &attributes )
563 bool fieldWasAdded {
false };
566 if ( !supportedType(
field ) )
570 bool isNativeTypeName =
false;
571 NativeType nativeTypeCandidate( QString(), QString(), QVariant::Invalid );
572 const QList<QgsVectorDataProvider::NativeType> nativeTypesList( nativeTypes() );
573 for (
const NativeType &nativeType : nativeTypesList )
575 if ( nativeType.mTypeName.toLower() ==
field.
typeName().toLower() )
577 isNativeTypeName =
true;
582 && nativeTypeCandidate.mType == QVariant::Invalid )
583 nativeTypeCandidate = nativeType;
585 if ( !isNativeTypeName )
587 if ( nativeTypeCandidate.mType == QVariant::Invalid )
597 mFields.append(
field );
598 fieldWasAdded =
true;
600 for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
604 attr.append( QVariant() );
608 return fieldWasAdded;
611 bool QgsMemoryProvider::renameAttributes(
const QgsFieldNameMap &renamedAttributes )
613 QgsFieldNameMap::const_iterator renameIt = renamedAttributes.constBegin();
615 for ( ; renameIt != renamedAttributes.constEnd(); ++renameIt )
617 const int fieldIndex = renameIt.key();
618 if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
623 if ( mFields.indexFromName( renameIt.value() ) >= 0 )
630 mFields.rename( fieldIndex, renameIt.value() );
635 bool QgsMemoryProvider::deleteAttributes(
const QgsAttributeIds &attributes )
637 QList<int> attrIdx = qgis::setToList( attributes );
638 std::sort( attrIdx.begin(), attrIdx.end(), std::greater<int>() );
641 for ( QList<int>::const_iterator it = attrIdx.constBegin(); it != attrIdx.constEnd(); ++it )
644 mFields.remove( idx );
646 for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
660 bool result {
true };
664 QString errorMessage;
665 for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
667 const QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
668 if ( fit == mFeatures.end() )
675 for ( QgsAttributeMap::const_iterator it2 = attrs.constBegin(); it2 != attrs.constEnd(); ++it2 )
677 QVariant attrValue = it2.value();
679 const bool conversionError { ! attrValue.isNull()
680 && ! mFields.at( it2.key() ).convertCompatible( attrValue, &errorMessage ) };
681 if ( conversionError )
686 pushError( tr(
"Could not change attribute %1 having type %2 for feature %4: %3" )
687 .arg( mFields.at( it2.key() ).name(), it2.value( ).typeName(),
688 errorMessage ).arg( it.key() ) );
693 rollBackAttrs.insert( it2.key(), fit->attribute( it2.key() ) );
694 fit->setAttribute( it2.key(), attrValue );
696 rollBackMap.insert( it.key(), rollBackAttrs );
702 changeAttributeValues( rollBackMap );
711 bool QgsMemoryProvider::changeGeometryValues(
const QgsGeometryMap &geometry_map )
713 for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
715 const QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
716 if ( fit == mFeatures.end() )
721 mSpatialIndex->deleteFeature( *fit );
723 fit->setGeometry( it.value() );
727 mSpatialIndex->addFeature( *fit );
735 QString QgsMemoryProvider::subsetString()
const
737 return mSubsetString;
740 bool QgsMemoryProvider::setSubsetString(
const QString &theSQL,
bool updateFeatureCount )
742 Q_UNUSED( updateFeatureCount )
744 if ( !theSQL.isEmpty() )
747 if ( tempExpression.hasParserError() )
751 if ( theSQL == mSubsetString )
754 mSubsetString = theSQL;
756 mExtent.setMinimal();
762 bool QgsMemoryProvider::createSpatialIndex()
764 if ( !mSpatialIndex )
769 for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
771 mSpatialIndex->addFeature( *it );
779 return mSpatialIndex ? SpatialIndexPresent : SpatialIndexNotPresent;
782 QgsVectorDataProvider::Capabilities QgsMemoryProvider::capabilities()
const
784 return AddFeatures | DeleteFeatures | ChangeGeometries |
785 ChangeAttributeValues | AddAttributes | DeleteAttributes | RenameAttributes | CreateSpatialIndex |
786 SelectAtId | CircularGeometries | FastTruncate;
789 bool QgsMemoryProvider::truncate()
793 mExtent.setMinimal();
797 void QgsMemoryProvider::updateExtents()
799 mExtent.setMinimal();
802 QString QgsMemoryProvider::name()
const
804 return TEXT_PROVIDER_KEY;
807 QString QgsMemoryProvider::description()
const
809 return TEXT_PROVIDER_DESCRIPTION;
813 QgsMemoryProviderMetadata::QgsMemoryProviderMetadata()
814 :
QgsProviderMetadata( QgsMemoryProvider::providerKey(), QgsMemoryProvider::providerDescription() )
818 QIcon QgsMemoryProviderMetadata::icon()
const
825 return new QgsMemoryProvider( uri, options, flags );
828 QList<QgsMapLayerType> QgsMemoryProviderMetadata::supportedLayerTypes()
const