30#include <QRegularExpression> 
   35#define TEXT_PROVIDER_KEY QStringLiteral( "memory" ) 
   36#define TEXT_PROVIDER_DESCRIPTION QStringLiteral( "Memory provider" ) 
   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 >()
 
  125  if ( query.hasQueryItem( QStringLiteral( 
"field" ) ) )
 
  127    QList<QgsField> attributes;
 
  128    const thread_local QRegularExpression reFieldDef( 
"\\:" 
  134        QRegularExpression::CaseInsensitiveOption );
 
  135    const QStringList fields = query.allQueryItemValues( QStringLiteral( 
"field" ) );
 
  136    for ( 
int i = 0; i < fields.size(); i++ )
 
  138      QString name = QUrl::fromPercentEncoding( fields.at( i ).toUtf8() );
 
  139      const QRegularExpressionMatch regularExpressionMatch = reFieldDef.match( name );
 
  142      QMetaType::Type type = QMetaType::Type::QString;
 
  143      QMetaType::Type subType = QMetaType::Type::UnknownType;
 
  144      QString 
typeName( QStringLiteral( 
"string" ) );
 
  148      if ( regularExpressionMatch.hasMatch() )
 
  150        name = name.mid( 0, regularExpressionMatch.capturedStart() );
 
  151        typeName = regularExpressionMatch.captured( 1 ).toLower();
 
  154        bool isNativeType = 
false;
 
  155        const QList<QgsVectorDataProvider::NativeType> nativeTypesList( nativeTypes() );
 
  156        for ( 
const NativeType &nativeType : nativeTypesList )
 
  158          if ( nativeType.mTypeName.toLower() == 
typeName )
 
  161            type = nativeType.mType;
 
  162            subType = nativeType.mSubType;
 
  169        if ( isNativeType == 
false )
 
  171          if ( 
typeName == QLatin1String( 
"int" ) )
 
  173            type = QMetaType::Type::Int;
 
  174            typeName = QStringLiteral( 
"integer" );
 
  176          else if ( 
typeName == QLatin1String( 
"long" ) )
 
  178            type = QMetaType::Type::LongLong;
 
  179            typeName = QStringLiteral( 
"int8" );
 
  181          else if ( 
typeName == QLatin1String( 
"bool" ) )
 
  183            type = QMetaType::Type::Bool;
 
  184            typeName = QStringLiteral( 
"boolean" );
 
  189            type = QMetaType::Type::QString;
 
  190            typeName = QStringLiteral( 
"string" );
 
  195        if ( 
typeName == QLatin1String( 
"real" ) || 
typeName == QLatin1String( 
"double" ) )
 
  201        if ( !regularExpressionMatch.captured( 2 ).isEmpty() )
 
  202          length = regularExpressionMatch.captured( 2 ).toInt();
 
  204        if ( !regularExpressionMatch.captured( 3 ).isEmpty() )
 
  205          precision = regularExpressionMatch.captured( 3 ).toInt();
 
  208        if ( !regularExpressionMatch.captured( 4 ).isEmpty() )
 
  210          if ( subType == QMetaType::Type::UnknownType )
 
  213          if ( type != QMetaType::Type::QVariantList && type != QMetaType::Type::QStringList )
 
  214            type = type == QMetaType::Type::QString ? QMetaType::Type::QStringList : QMetaType::Type::QVariantList;
 
  216          const QLatin1String listSuffix( 
"list" );
 
  217          if ( !
typeName.endsWith( listSuffix ) )
 
  218            typeName += QLatin1String( 
"list" );
 
  224    addAttributes( attributes );
 
  227  if ( query.hasQueryItem( QStringLiteral( 
"index" ) ) && query.queryItemValue( QStringLiteral( 
"index" ) ) == QLatin1String( 
"yes" ) )
 
  229    createSpatialIndex();
 
  234QgsMemoryProvider::~QgsMemoryProvider()
 
  236  delete mSpatialIndex;
 
  239QString QgsMemoryProvider::providerKey()
 
  241  return TEXT_PROVIDER_KEY;
 
  244QString QgsMemoryProvider::providerDescription()
 
  246  return TEXT_PROVIDER_DESCRIPTION;
 
  251  return new QgsMemoryFeatureSource( 
this );
 
  254QString QgsMemoryProvider::dataSourceUri( 
bool expandAuthConfig )
 const 
  256  Q_UNUSED( expandAuthConfig )
 
  258  QUrl uri( QStringLiteral( 
"memory" ) );
 
  261  query.addQueryItem( QStringLiteral( 
"geometry" ), geometry );
 
  263  if ( mCrs.isValid() )
 
  266    const QString authid = mCrs.authid();
 
  267    if ( authid.startsWith( QLatin1String( 
"EPSG:" ) ) )
 
  275    query.addQueryItem( QStringLiteral( 
"crs" ), crsDef );
 
  279    query.addQueryItem( QStringLiteral( 
"index" ), QStringLiteral( 
"yes" ) );
 
  283  for ( 
int i = 0; i < attrs.size(); i++ )
 
  285    const QgsField field = mFields.at( attrs[i] );
 
  286    QString fieldDef = field.
name();
 
  290    if ( field.
type() == QMetaType::Type::QVariantList || field.
type() == QMetaType::Type::QStringList )
 
  294        case QMetaType::Type::Int:
 
  295          typeName = QStringLiteral( 
"integer" );
 
  298        case QMetaType::Type::LongLong:
 
  299          typeName = QStringLiteral( 
"long" );
 
  302        case QMetaType::Type::Double:
 
  303          typeName = QStringLiteral( 
"double" );
 
  306        case QMetaType::Type::QString:
 
  307          typeName = QStringLiteral( 
"string" );
 
  316    fieldDef.append( QStringLiteral( 
":%2(%3,%4)%5" ).arg( 
typeName ).arg( field.
length() ).arg( field.
precision() ).arg( isList ? QStringLiteral( 
"[]" ) : QString() ) );
 
  317    query.addQueryItem( QStringLiteral( 
"field" ), fieldDef );
 
  319  uri.setQuery( query );
 
  321  return QString( uri.toEncoded() );
 
  325QString QgsMemoryProvider::storageType()
 const 
  327  return QStringLiteral( 
"Memory storage" );
 
  332  return QgsFeatureIterator( 
new QgsMemoryFeatureIterator( 
new QgsMemoryFeatureSource( 
this ), 
true, request ) );
 
  338  if ( mExtent.isEmpty() && !mFeatures.isEmpty() )
 
  341    if ( mSubsetString.isEmpty() )
 
  344      const auto constMFeatures = mFeatures;
 
  345      for ( 
const QgsFeature &feat : constMFeatures )
 
  347        if ( feat.hasGeometry() )
 
  348          mExtent.combineExtentWith( feat.geometry().boundingBox() );
 
  362  else if ( mFeatures.isEmpty() )
 
  375long long QgsMemoryProvider::featureCount()
 const 
  377  if ( mSubsetString.isEmpty() )
 
  378    return mFeatures.count();
 
  391QgsFields QgsMemoryProvider::fields()
 const 
  396bool QgsMemoryProvider::isValid()
 const 
  409  if ( QgsMemoryProvider *other = qobject_cast< QgsMemoryProvider * >( source ) )
 
  412    mFeatures = other->mFeatures;
 
  413    mNextFeatureId = other->mNextFeatureId;
 
  414    mExtent = other->mExtent;
 
  419bool QgsMemoryProvider::addFeatures( 
QgsFeatureList &flist, Flags flags )
 
  423  const bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
 
  425  const int fieldCount = mFields.count();
 
  428  const auto oldExtent { mExtent };
 
  429  const auto oldNextFeatureId { mNextFeatureId };
 
  432  for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end() && result ; ++it )
 
  434    it->setId( mNextFeatureId );
 
  435    it->setValid( 
true );
 
  436    const int attributeCount = it->attributeCount();
 
  437    if ( attributeCount < fieldCount )
 
  442      for ( 
int i = attributeCount; i < mFields.count(); ++i )
 
  446      it->setAttributes( attributes );
 
  448    else if ( attributeCount > fieldCount )
 
  451      pushError( tr( 
"Feature has too many attributes (expecting %1, received %2)" ).arg( fieldCount ).arg( attributeCount ) );
 
  453      attributes.resize( mFields.count() );
 
  454      it->setAttributes( attributes );
 
  464      pushError( tr( 
"Could not add feature with geometry type %1 to layer of type %2" ).arg( 
QgsWkbTypes::displayString( it->geometry().wkbType() ),
 
  471    bool conversionError { 
false };
 
  472    QString errorMessage;
 
  473    for ( 
int i = 0; i < mFields.count(); ++i )
 
  475      const QVariant originalValue = it->attribute( i );
 
  476      QVariant attrValue = originalValue;
 
  477      if ( ! 
QgsVariantUtils::isNull( attrValue ) && ! mFields.at( i ).convertCompatible( attrValue, &errorMessage ) )
 
  482          pushError( tr( 
"Could not store attribute \"%1\": %2" )
 
  483                     .arg( mFields.at( i ).name(), errorMessage ) );
 
  486        conversionError = 
true;
 
  489      else if ( attrValue.userType() != originalValue.userType() )
 
  492        it->setAttribute( i, attrValue );
 
  497    if ( conversionError )
 
  506    mFeatures.insert( mNextFeatureId, *it );
 
  507    addedFids.insert( mNextFeatureId );
 
  509    if ( it->hasGeometry() )
 
  512        mExtent.combineExtentWith( it->geometry().boundingBox() );
 
  516        mSpatialIndex->addFeature( *it );
 
  527      mFeatures.remove( addedFid );
 
  530    mNextFeatureId = oldNextFeatureId;
 
  540bool QgsMemoryProvider::deleteFeatures( 
const QgsFeatureIds &
id )
 
  542  for ( QgsFeatureIds::const_iterator it = 
id.begin(); it != 
id.end(); ++it )
 
  544    const QgsFeatureMap::iterator fit = mFeatures.find( *it );
 
  547    if ( fit == mFeatures.end() )
 
  552      mSpatialIndex->deleteFeature( *fit );
 
  554    mFeatures.erase( fit );
 
  563bool QgsMemoryProvider::addAttributes( 
const QList<QgsField> &attributes )
 
  565  bool fieldWasAdded { 
false };
 
  568    if ( !supportedType( field ) )
 
  572    bool isNativeTypeName = 
false;
 
  573    NativeType nativeTypeCandidate( QString(), QString(), QMetaType::Type::UnknownType );
 
  574    const QList<QgsVectorDataProvider::NativeType> nativeTypesList( nativeTypes() );
 
  575    for ( 
const NativeType &nativeType : nativeTypesList )
 
  577      if ( nativeType.mTypeName.toLower() == field.
typeName().toLower() )
 
  579        isNativeTypeName = 
true;
 
  583      if ( nativeType.mType == field.
type()
 
  584           && nativeTypeCandidate.mType == QMetaType::Type::UnknownType )
 
  585        nativeTypeCandidate = nativeType;
 
  587    if ( !isNativeTypeName )
 
  589      if ( nativeTypeCandidate.mType == QMetaType::Type::UnknownType )
 
  595      field.
setTypeName( nativeTypeCandidate.mTypeName );
 
  599    mFields.append( field );
 
  600    fieldWasAdded = 
true;
 
  602    for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
 
  606      attr.append( QVariant() );
 
  610  return fieldWasAdded;
 
  613bool QgsMemoryProvider::renameAttributes( 
const QgsFieldNameMap &renamedAttributes )
 
  615  QgsFieldNameMap::const_iterator renameIt = renamedAttributes.constBegin();
 
  617  for ( ; renameIt != renamedAttributes.constEnd(); ++renameIt )
 
  619    const int fieldIndex = renameIt.key();
 
  620    if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
 
  625    if ( mFields.indexFromName( renameIt.value() ) >= 0 )
 
  632    mFields.rename( fieldIndex, renameIt.value() );
 
  637bool QgsMemoryProvider::deleteAttributes( 
const QgsAttributeIds &attributes )
 
  639  QList<int> attrIdx( attributes.begin(), attributes.end() );
 
  640  std::sort( attrIdx.begin(), attrIdx.end(), std::greater<int>() );
 
  643  for ( QList<int>::const_iterator it = attrIdx.constBegin(); it != attrIdx.constEnd(); ++it )
 
  646    mFields.remove( idx );
 
  648    for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
 
  662  bool result { 
true };
 
  666  QString errorMessage;
 
  667  for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
 
  669    const QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
 
  670    if ( fit == mFeatures.end() )
 
  677    for ( QgsAttributeMap::const_iterator it2 = attrs.constBegin(); it2 != attrs.constEnd(); ++it2 )
 
  679      const int fieldIndex = it2.key();
 
  680      if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
 
  683      QVariant attrValue = it2.value();
 
  686                                   && ! mFields.at( it2.key() ).convertCompatible( attrValue, &errorMessage ) };
 
  687      if ( conversionError )
 
  692          pushError( tr( 
"Could not change attribute %1 having type %2 for feature %4: %3" )
 
  693                     .arg( mFields.at( it2.key() ).name(), it2.value( ).typeName(),
 
  694                           errorMessage ).arg( it.key() ) );
 
  699      rollBackAttrs.insert( it2.key(), fit->attribute( it2.key() ) );
 
  700      fit->setAttribute( it2.key(), attrValue );
 
  702    rollBackMap.insert( it.key(), rollBackAttrs );
 
  708    changeAttributeValues( rollBackMap );
 
  717bool QgsMemoryProvider::changeGeometryValues( 
const QgsGeometryMap &geometry_map )
 
  719  for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
 
  721    const QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
 
  722    if ( fit == mFeatures.end() )
 
  727      mSpatialIndex->deleteFeature( *fit );
 
  729    fit->setGeometry( it.value() );
 
  733      mSpatialIndex->addFeature( *fit );
 
  741QString QgsMemoryProvider::subsetString()
 const 
  743  return mSubsetString;
 
  746bool QgsMemoryProvider::setSubsetString( 
const QString &theSQL, 
bool updateFeatureCount )
 
  748  Q_UNUSED( updateFeatureCount )
 
  750  if ( !theSQL.isEmpty() )
 
  753    if ( tempExpression.hasParserError() )
 
  757  if ( theSQL == mSubsetString )
 
  760  mSubsetString = theSQL;
 
  768bool QgsMemoryProvider::supportsSubsetString()
 const 
  773QString QgsMemoryProvider::subsetStringDialect()
 const 
  775  return tr( 
"QGIS expression" );
 
  778QString QgsMemoryProvider::subsetStringHelpUrl()
 const 
  784bool QgsMemoryProvider::createSpatialIndex()
 
  786  if ( !mSpatialIndex )
 
  791    for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
 
  793      mSpatialIndex->addFeature( *it );
 
  811bool QgsMemoryProvider::truncate()
 
  819void QgsMemoryProvider::updateExtents()
 
  824QString QgsMemoryProvider::name()
 const 
  826  return TEXT_PROVIDER_KEY;
 
  829QString QgsMemoryProvider::description()
 const 
  831  return TEXT_PROVIDER_DESCRIPTION;
 
  835QgsMemoryProviderMetadata::QgsMemoryProviderMetadata()
 
  836  : 
QgsProviderMetadata( QgsMemoryProvider::providerKey(), QgsMemoryProvider::providerDescription() )
 
  840QIcon QgsMemoryProviderMetadata::icon()
 const 
  847  return new QgsMemoryProvider( uri, options, flags );
 
  850QList<Qgis::LayerType> QgsMemoryProviderMetadata::supportedLayerTypes()
 const 
@ SelectAtId
Fast access to features using their ID.
 
@ FastTruncate
Supports fast truncation of the layer (removing all features)
 
@ AddFeatures
Allows adding features.
 
@ CircularGeometries
Supports circular geometry types (circularstring, compoundcurve, curvepolygon)
 
@ ChangeGeometries
Allows modifications of geometries.
 
@ AddAttributes
Allows addition of new attributes (fields)
 
@ CreateSpatialIndex
Allows creation of spatial index.
 
@ RenameAttributes
Supports renaming attributes (fields)
 
@ DeleteFeatures
Allows deletion of features.
 
@ DeleteAttributes
Allows deletion of attributes (fields)
 
@ ChangeAttributeValues
Allows modification of attribute values.
 
SpatialIndexPresence
Enumeration of spatial index presence states.
 
@ NotPresent
No spatial index exists for the source.
 
@ Present
A valid spatial index exists for the source.
 
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
 
QFlags< VectorProviderCapability > VectorProviderCapabilities
Vector data provider capabilities.
 
WkbType
The WKB type describes the number of dimensions a geometry has.
 
@ Preferred
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
 
Base class that can be used for any class that is capable of returning features.
 
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
 
This class represents a coordinate reference system (CRS).
 
Abstract base class for spatial data provider implementations.
 
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)
Fetch next feature and stores in f, returns true on success.
 
This class wraps a request for features to a vector layer (or directly its vector data provider).
 
@ RollBackOnErrors
Roll back the whole transaction if a single add feature operation fails.
 
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.
 
QMetaType::Type subType() const
If the field is a collection, gets its element's type.
 
void setTypeName(const QString &typeName)
Set the field type.
 
Container of fields for a vector layer.
 
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
 
static void warning(const QString &msg)
Goes to qWarning.
 
A rectangle specified with double values.
 
void setNull()
Mark a rectangle as being null (holding no spatial information).
 
A spatial index for QgsFeature objects.
 
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
 
static QString typeToDisplayString(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType)
Returns a user-friendly translated string representing a QVariant type.
 
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
 
This is the base class for vector data providers.
 
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
 
static Qgis::WkbType parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
 
static QString displayString(Qgis::WkbType type)
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 QgsAttributeList & attributeIndexes
 
Setting options for creating vector data providers.