32 #define TEXT_PROVIDER_KEY QStringLiteral( "memory" )
 
   33 #define TEXT_PROVIDER_DESCRIPTION QStringLiteral( "Memory provider" )
 
   35 QgsMemoryProvider::QgsMemoryProvider( 
const QString &uri, 
const ProviderOptions &options, QgsDataProvider::ReadFlags flags )
 
   40   QUrl url = QUrl::fromEncoded( uri.toUtf8() );
 
   41   const QUrlQuery query( url );
 
   43   if ( query.hasQueryItem( QStringLiteral( 
"geometry" ) ) )
 
   45     geometry = query.queryItemValue( QStringLiteral( 
"geometry" ) );
 
   49     geometry = url.path();
 
   52   if ( geometry.compare( QLatin1String( 
"none" ), Qt::CaseInsensitive ) == 0 )
 
   61   if ( query.hasQueryItem( QStringLiteral( 
"crs" ) ) )
 
   63     QString crsDef = query.queryItemValue( QStringLiteral( 
"crs" ) );
 
   64     mCrs.createFromString( crsDef );
 
   75   setNativeTypes( QList< NativeType >()
 
  119   if ( query.hasQueryItem( QStringLiteral( 
"field" ) ) )
 
  121     QList<QgsField> attributes;
 
  122     QRegExp reFieldDef( 
"\\:" 
  123                         "(int|integer|long|int8|real|double|string|date|time|datetime|binary|bool|boolean)"  
  127                         "$", Qt::CaseInsensitive );
 
  128     QStringList fields = query.allQueryItemValues( QStringLiteral( 
"field" ) );
 
  129     for ( 
int i = 0; i < fields.size(); i++ )
 
  131       QString name = QUrl::fromPercentEncoding( fields.at( i ).toUtf8() );
 
  132       QVariant::Type type = QVariant::String;
 
  133       QVariant::Type subType = QVariant::Invalid;
 
  134       QString 
typeName( QStringLiteral( 
"string" ) );
 
  138       int pos = reFieldDef.indexIn( name );
 
  141         name = name.mid( 0, pos );
 
  142         typeName = reFieldDef.cap( 1 ).toLower();
 
  143         if ( 
typeName == QLatin1String( 
"int" ) || 
typeName == QLatin1String( 
"integer" ) )
 
  145           type = QVariant::Int;
 
  146           typeName = QStringLiteral( 
"integer" );
 
  149         else if ( 
typeName == QLatin1String( 
"int8" ) || 
typeName == QLatin1String( 
"long" ) )
 
  151           type = QVariant::LongLong;
 
  152           typeName = QStringLiteral( 
"int8" );
 
  155         else if ( 
typeName == QLatin1String( 
"real" ) || 
typeName == QLatin1String( 
"double" ) )
 
  157           type = QVariant::Double;
 
  158           typeName = QStringLiteral( 
"double" );
 
  162         else if ( 
typeName == QLatin1String( 
"date" ) )
 
  164           type = QVariant::Date;
 
  165           typeName = QStringLiteral( 
"date" );
 
  168         else if ( 
typeName == QLatin1String( 
"time" ) )
 
  170           type = QVariant::Time;
 
  171           typeName = QStringLiteral( 
"time" );
 
  174         else if ( 
typeName == QLatin1String( 
"datetime" ) )
 
  176           type = QVariant::DateTime;
 
  177           typeName = QStringLiteral( 
"datetime" );
 
  180         else if ( 
typeName == QLatin1String( 
"bool" ) || 
typeName == QLatin1String( 
"boolean" ) )
 
  182           type = QVariant::Bool;
 
  183           typeName = QStringLiteral( 
"boolean" );
 
  186         else if ( 
typeName == QLatin1String( 
"binary" ) )
 
  188           type = QVariant::ByteArray;
 
  189           typeName = QStringLiteral( 
"binary" );
 
  193         if ( !reFieldDef.cap( 2 ).isEmpty() )
 
  195           length = reFieldDef.cap( 2 ).toInt();
 
  197         if ( !reFieldDef.cap( 3 ).isEmpty() )
 
  201         if ( !reFieldDef.cap( 4 ).isEmpty() )
 
  205           type = type == QVariant::String ? QVariant::StringList : QVariant::List;
 
  206           typeName += QLatin1String( 
"list" );
 
  209       if ( !name.isEmpty() )
 
  212     addAttributes( attributes );
 
  215   if ( query.hasQueryItem( QStringLiteral( 
"index" ) ) && query.queryItemValue( QStringLiteral( 
"index" ) ) == QLatin1String( 
"yes" ) )
 
  217     createSpatialIndex();
 
  222 QgsMemoryProvider::~QgsMemoryProvider()
 
  224   delete mSpatialIndex;
 
  227 QString QgsMemoryProvider::providerKey()
 
  229   return TEXT_PROVIDER_KEY;
 
  232 QString QgsMemoryProvider::providerDescription()
 
  234   return TEXT_PROVIDER_DESCRIPTION;
 
  237 QgsMemoryProvider *QgsMemoryProvider::createProvider( 
const QString &uri,
 
  238     const ProviderOptions &options,
 
  239     QgsDataProvider::ReadFlags flags )
 
  241   return new QgsMemoryProvider( uri, options, flags );
 
  246   return new QgsMemoryFeatureSource( 
this );
 
  249 QString QgsMemoryProvider::dataSourceUri( 
bool expandAuthConfig )
 const 
  251   Q_UNUSED( expandAuthConfig )
 
  253   QUrl uri( QStringLiteral( 
"memory" ) );
 
  256   query.addQueryItem( QStringLiteral( 
"geometry" ), geometry );
 
  258   if ( mCrs.isValid() )
 
  261     QString authid = mCrs.authid();
 
  262     if ( authid.startsWith( QLatin1String( 
"EPSG:" ) ) )
 
  270     query.addQueryItem( QStringLiteral( 
"crs" ), crsDef );
 
  274     query.addQueryItem( QStringLiteral( 
"index" ), QStringLiteral( 
"yes" ) );
 
  278   for ( 
int i = 0; i < attrs.size(); i++ )
 
  290           typeName = QStringLiteral( 
"integer" );
 
  293         case QVariant::LongLong:
 
  294           typeName = QStringLiteral( 
"long" );
 
  297         case QVariant::Double:
 
  298           typeName = QStringLiteral( 
"double" );
 
  301         case QVariant::String:
 
  302           typeName = QStringLiteral( 
"string" );
 
  311     fieldDef.append( QStringLiteral( 
":%2(%3,%4)%5" ).arg( 
typeName ).arg( 
field.
length() ).arg( 
field.
precision() ).arg( isList ? QStringLiteral( 
"[]" ) : QString() ) );
 
  312     query.addQueryItem( QStringLiteral( 
"field" ), fieldDef );
 
  314   uri.setQuery( query );
 
  316   return QString( uri.toEncoded() );
 
  320 QString QgsMemoryProvider::storageType()
 const 
  322   return QStringLiteral( 
"Memory storage" );
 
  327   return QgsFeatureIterator( 
new QgsMemoryFeatureIterator( 
new QgsMemoryFeatureSource( 
this ), 
true, request ) );
 
  333   if ( mExtent.isEmpty() && !mFeatures.isEmpty() )
 
  336     if ( mSubsetString.isEmpty() )
 
  339       const auto constMFeatures = mFeatures;
 
  340       for ( 
const QgsFeature &feat : constMFeatures )
 
  342         if ( feat.hasGeometry() )
 
  343           mExtent.combineExtentWith( feat.geometry().boundingBox() );
 
  357   else if ( mFeatures.isEmpty() )
 
  359     mExtent.setMinimal();
 
  370 long long QgsMemoryProvider::featureCount()
 const 
  372   if ( mSubsetString.isEmpty() )
 
  373     return mFeatures.count();
 
  386 QgsFields QgsMemoryProvider::fields()
 const 
  391 bool QgsMemoryProvider::isValid()
 const 
  404   if ( QgsMemoryProvider *other = qobject_cast< QgsMemoryProvider * >( source ) )
 
  407     mFeatures = other->mFeatures;
 
  408     mNextFeatureId = other->mNextFeatureId;
 
  409     mExtent = other->mExtent;
 
  414 bool QgsMemoryProvider::addFeatures( 
QgsFeatureList &flist, Flags flags )
 
  418   bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
 
  420   int fieldCount = mFields.count();
 
  423   const auto oldExtent { mExtent };
 
  424   const auto oldNextFeatureId { mNextFeatureId };
 
  427   for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end() && result ; ++it )
 
  429     it->setId( mNextFeatureId );
 
  430     it->setValid( 
true );
 
  431     if ( it->attributes().count() < fieldCount )
 
  436       for ( 
int i = it->attributes().count(); i < mFields.count(); ++i )
 
  438         attributes.append( QVariant( mFields.at( i ).type() ) );
 
  440       it->setAttributes( attributes );
 
  442     else if ( it->attributes().count() > fieldCount )
 
  445       pushError( tr( 
"Feature has too many attributes (expecting %1, received %2)" ).arg( fieldCount ).arg( it->attributes().count() ) );
 
  447       attributes.resize( mFields.count() );
 
  448       it->setAttributes( attributes );
 
  458       pushError( tr( 
"Could not add feature with geometry type %1 to layer of type %2" ).arg( 
QgsWkbTypes::displayString( it->geometry().wkbType() ),
 
  465     bool conversionError { 
false };
 
  466     QString errorMessage;
 
  467     for ( 
int i = 0; i < mFields.count(); ++i )
 
  469       const QVariant originalValue = it->attribute( i );
 
  470       QVariant attrValue = originalValue;
 
  471       if ( ! attrValue.isNull() && ! mFields.at( i ).convertCompatible( attrValue, &errorMessage ) )
 
  476           pushError( tr( 
"Could not store attribute \"%1\": %2" )
 
  477                      .arg( mFields.at( i ).name(), errorMessage ) );
 
  480         conversionError = 
true;
 
  483       else if ( attrValue.type() != originalValue.type() )
 
  486         it->setAttribute( i, attrValue );
 
  491     if ( conversionError )
 
  493       if ( flags.testFlag( QgsFeatureSink::Flag::RollBackOnErrors ) )
 
  500     mFeatures.insert( mNextFeatureId, *it );
 
  501     addedFids.insert( mNextFeatureId );
 
  503     if ( it->hasGeometry() )
 
  506         mExtent.combineExtentWith( it->geometry().boundingBox() );
 
  510         mSpatialIndex->addFeature( *it );
 
  517   if ( ! result && flags.testFlag( QgsFeatureSink::Flag::RollBackOnErrors ) )
 
  521       mFeatures.remove( addedFid );
 
  524     mNextFeatureId = oldNextFeatureId;
 
  534 bool QgsMemoryProvider::deleteFeatures( 
const QgsFeatureIds &
id )
 
  536   for ( QgsFeatureIds::const_iterator it = 
id.begin(); it != 
id.end(); ++it )
 
  538     QgsFeatureMap::iterator fit = mFeatures.find( *it );
 
  541     if ( fit == mFeatures.end() )
 
  546       mSpatialIndex->deleteFeature( *fit );
 
  548     mFeatures.erase( fit );
 
  557 bool QgsMemoryProvider::addAttributes( 
const QList<QgsField> &attributes )
 
  559   for ( QList<QgsField>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
 
  561     switch ( it->type() )
 
  564       case QVariant::Double:
 
  565       case QVariant::String:
 
  568       case QVariant::DateTime:
 
  569       case QVariant::LongLong:
 
  570       case QVariant::StringList:
 
  573       case QVariant::ByteArray:
 
  576         QgsDebugMsg( 
"Field type not supported: " + it->typeName() );
 
  580     mFields.append( *it );
 
  582     for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
 
  586       attr.append( QVariant() );
 
  593 bool QgsMemoryProvider::renameAttributes( 
const QgsFieldNameMap &renamedAttributes )
 
  595   QgsFieldNameMap::const_iterator renameIt = renamedAttributes.constBegin();
 
  597   for ( ; renameIt != renamedAttributes.constEnd(); ++renameIt )
 
  599     int fieldIndex = renameIt.key();
 
  600     if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
 
  605     if ( mFields.indexFromName( renameIt.value() ) >= 0 )
 
  612     mFields.rename( fieldIndex, renameIt.value() );
 
  617 bool QgsMemoryProvider::deleteAttributes( 
const QgsAttributeIds &attributes )
 
  619   QList<int> attrIdx = qgis::setToList( attributes );
 
  620   std::sort( attrIdx.begin(), attrIdx.end(), std::greater<int>() );
 
  623   for ( QList<int>::const_iterator it = attrIdx.constBegin(); it != attrIdx.constEnd(); ++it )
 
  626     mFields.remove( idx );
 
  628     for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
 
  642   bool result { 
true };
 
  646   QString errorMessage;
 
  647   for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
 
  649     QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
 
  650     if ( fit == mFeatures.end() )
 
  657     for ( QgsAttributeMap::const_iterator it2 = attrs.constBegin(); it2 != attrs.constEnd(); ++it2 )
 
  659       QVariant attrValue = it2.value();
 
  661       const bool conversionError { ! attrValue.isNull()
 
  662                                    && ! mFields.at( it2.key() ).convertCompatible( attrValue, &errorMessage ) };
 
  663       if ( conversionError )
 
  668           pushError( tr( 
"Could not change attribute %1 having type %2 for feature %4: %3" )
 
  669                      .arg( mFields.at( it2.key() ).name(), it2.value( ).typeName(),
 
  670                            errorMessage ).arg( it.key() ) );
 
  675       rollBackAttrs.insert( it2.key(), fit->attribute( it2.key() ) );
 
  676       fit->setAttribute( it2.key(), attrValue );
 
  678     rollBackMap.insert( it.key(), rollBackAttrs );
 
  684     changeAttributeValues( rollBackMap );
 
  693 bool QgsMemoryProvider::changeGeometryValues( 
const QgsGeometryMap &geometry_map )
 
  695   for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
 
  697     QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
 
  698     if ( fit == mFeatures.end() )
 
  703       mSpatialIndex->deleteFeature( *fit );
 
  705     fit->setGeometry( it.value() );
 
  709       mSpatialIndex->addFeature( *fit );
 
  717 QString QgsMemoryProvider::subsetString()
 const 
  719   return mSubsetString;
 
  722 bool QgsMemoryProvider::setSubsetString( 
const QString &theSQL, 
bool updateFeatureCount )
 
  724   Q_UNUSED( updateFeatureCount )
 
  726   if ( !theSQL.isEmpty() )
 
  729     if ( tempExpression.hasParserError() )
 
  733   if ( theSQL == mSubsetString )
 
  736   mSubsetString = theSQL;
 
  738   mExtent.setMinimal();
 
  744 bool QgsMemoryProvider::createSpatialIndex()
 
  746   if ( !mSpatialIndex )
 
  751     for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
 
  753       mSpatialIndex->addFeature( *it );
 
  761   return mSpatialIndex ? SpatialIndexPresent : SpatialIndexNotPresent;
 
  764 QgsVectorDataProvider::Capabilities QgsMemoryProvider::capabilities()
 const 
  766   return AddFeatures | DeleteFeatures | ChangeGeometries |
 
  767          ChangeAttributeValues | AddAttributes | DeleteAttributes | RenameAttributes | CreateSpatialIndex |
 
  768          SelectAtId | CircularGeometries | FastTruncate;
 
  771 bool QgsMemoryProvider::truncate()
 
  775   mExtent.setMinimal();
 
  779 void QgsMemoryProvider::updateExtents()
 
  781   mExtent.setMinimal();
 
  784 QString QgsMemoryProvider::name()
 const 
  786   return TEXT_PROVIDER_KEY;
 
  789 QString QgsMemoryProvider::description()
 const 
  791   return TEXT_PROVIDER_DESCRIPTION;
 
Base class that can be used for any class that is capable of returning features.
This class represents a coordinate reference system (CRS).
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
Class for parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
SpatialIndexPresence
Enumeration of spatial index presence states.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Encapsulate a field in an attribute table or data source.
QString typeName() const
Gets the field type.
QVariant::Type subType() const
If the field is a collection, gets its element's type.
Container of fields for a vector layer.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
A rectangle specified with double values.
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
A spatial index for QgsFeature objects.
This is the base class for vector data providers.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
Type
The WKB type describes the number of dimensions a geometry has.
static QString displayString(Type type) SIP_HOLDGIL
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
QMap< int, QString > QgsFieldNameMap
QMap< int, QVariant > QgsAttributeMap
QMap< QgsFeatureId, QgsGeometry > QgsGeometryMap
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
QList< QgsFeature > QgsFeatureList
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
QSet< int > QgsAttributeIds
const QgsCoordinateReferenceSystem & crs
const QgsAttributeList & attributeIndexes