QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsmemoryprovider.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  memoryprovider.cpp - provider with storage in memory
3  ------------------
4  begin : June 2008
5  copyright : (C) 2008 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsmemoryprovider.h"
18 
19 #include "qgsfeature.h"
20 #include "qgsfields.h"
21 #include "qgsgeometry.h"
22 #include "qgslogger.h"
23 #include "qgsspatialindex.h"
25 
26 #include <QUrl>
27 #include <QUrlQuery>
28 #include <QRegExp>
29 
31 
32 #define TEXT_PROVIDER_KEY QStringLiteral( "memory" )
33 #define TEXT_PROVIDER_DESCRIPTION QStringLiteral( "Memory provider" )
34 
35 QgsMemoryProvider::QgsMemoryProvider( const QString &uri, const ProviderOptions &options, QgsDataProvider::ReadFlags flags )
36  : QgsVectorDataProvider( uri, options, flags )
37 {
38  // Initialize the geometry with the uri to support old style uri's
39  // (ie, just 'point', 'line', 'polygon')
40  QUrl url = QUrl::fromEncoded( uri.toUtf8() );
41  const QUrlQuery query( url );
42  QString geometry;
43  if ( query.hasQueryItem( QStringLiteral( "geometry" ) ) )
44  {
45  geometry = query.queryItemValue( QStringLiteral( "geometry" ) );
46  }
47  else
48  {
49  geometry = url.path();
50  }
51 
52  if ( geometry.compare( QLatin1String( "none" ), Qt::CaseInsensitive ) == 0 )
53  {
54  mWkbType = QgsWkbTypes::NoGeometry;
55  }
56  else
57  {
58  mWkbType = QgsWkbTypes::parseType( geometry );
59  }
60 
61  if ( query.hasQueryItem( QStringLiteral( "crs" ) ) )
62  {
63  QString crsDef = query.queryItemValue( QStringLiteral( "crs" ) );
64  mCrs.createFromString( crsDef );
65  }
66  else
67  {
68  // TODO - remove in QGIS 4.0. Layers without an explicit CRS set SHOULD have an invalid CRS. But in order to maintain
69  // 3.x api, we have to be tolerant/shortsighted(?) here and fallback to EPSG:4326
70  mCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) );
71  }
72 
73  mNextFeatureId = 1;
74 
75  setNativeTypes( QList< NativeType >()
76  << QgsVectorDataProvider::NativeType( tr( "Whole number (integer)" ), QStringLiteral( "integer" ), QVariant::Int, 0, 10 )
77  // Decimal number from OGR/Shapefile/dbf may come with length up to 32 and
78  // precision up to length-2 = 30 (default, if width is not specified in dbf is length = 24 precision = 15)
79  // We know that double (QVariant::Double) has only 15-16 significant numbers,
80  // but setting that correct limits would disable the use of memory provider with
81  // data from Shapefiles. In any case, the data are handled as doubles.
82  // So the limits set here are not correct but enable use of data from Shapefiles.
83  << QgsVectorDataProvider::NativeType( tr( "Decimal number (real)" ), QStringLiteral( "double" ), QVariant::Double, 0, 32, 0, 30 )
84  << QgsVectorDataProvider::NativeType( tr( "Text (string)" ), QStringLiteral( "string" ), QVariant::String, 0, 255 )
85 
86  // date type
87  << QgsVectorDataProvider::NativeType( tr( "Date" ), QStringLiteral( "date" ), QVariant::Date, -1, -1, -1, -1 )
88  << QgsVectorDataProvider::NativeType( tr( "Time" ), QStringLiteral( "time" ), QVariant::Time, -1, -1, -1, -1 )
89  << QgsVectorDataProvider::NativeType( tr( "Date & Time" ), QStringLiteral( "datetime" ), QVariant::DateTime, -1, -1, -1, -1 )
90 
91  // integer types
92  << QgsVectorDataProvider::NativeType( tr( "Whole number (smallint - 16bit)" ), QStringLiteral( "int2" ), QVariant::Int, -1, -1, 0, 0 )
93  << QgsVectorDataProvider::NativeType( tr( "Whole number (integer - 32bit)" ), QStringLiteral( "int4" ), QVariant::Int, -1, -1, 0, 0 )
94  << QgsVectorDataProvider::NativeType( tr( "Whole number (integer - 64bit)" ), QStringLiteral( "int8" ), QVariant::LongLong, -1, -1, 0, 0 )
95  << QgsVectorDataProvider::NativeType( tr( "Decimal number (numeric)" ), QStringLiteral( "numeric" ), QVariant::Double, 1, 20, 0, 20 )
96  << QgsVectorDataProvider::NativeType( tr( "Decimal number (decimal)" ), QStringLiteral( "decimal" ), QVariant::Double, 1, 20, 0, 20 )
97 
98  // floating point
99  << QgsVectorDataProvider::NativeType( tr( "Decimal number (real)" ), QStringLiteral( "real" ), QVariant::Double, -1, -1, -1, -1 )
100  << QgsVectorDataProvider::NativeType( tr( "Decimal number (double)" ), QStringLiteral( "double precision" ), QVariant::Double, -1, -1, -1, -1 )
101 
102  // string types
103  << QgsVectorDataProvider::NativeType( tr( "Text, unlimited length (text)" ), QStringLiteral( "text" ), QVariant::String, -1, -1, -1, -1 )
104 
105  // boolean
106  << QgsVectorDataProvider::NativeType( tr( "Boolean" ), QStringLiteral( "bool" ), QVariant::Bool )
107 
108  // blob
109  << QgsVectorDataProvider::NativeType( tr( "Binary object (BLOB)" ), QStringLiteral( "binary" ), QVariant::ByteArray )
110 
111  );
112 
113  if ( query.hasQueryItem( QStringLiteral( "field" ) ) )
114  {
115  QList<QgsField> attributes;
116  QRegExp reFieldDef( "\\:"
117  "(int|integer|long|int8|real|double|string|date|time|datetime|binary|bool|boolean)" // type
118  "(?:\\((\\-?\\d+)" // length
119  "(?:\\,(\\-?\\d+))?" // precision
120  "\\))?(\\[\\])?" // array
121  "$", Qt::CaseInsensitive );
122  QStringList fields = query.allQueryItemValues( QStringLiteral( "field" ) );
123  for ( int i = 0; i < fields.size(); i++ )
124  {
125  QString name = QUrl::fromPercentEncoding( fields.at( i ).toUtf8() );
126  QVariant::Type type = QVariant::String;
127  QVariant::Type subType = QVariant::Invalid;
128  QString typeName( QStringLiteral( "string" ) );
129  int length = 255;
130  int precision = 0;
131 
132  int pos = reFieldDef.indexIn( name );
133  if ( pos >= 0 )
134  {
135  name = name.mid( 0, pos );
136  typeName = reFieldDef.cap( 1 ).toLower();
137  if ( typeName == QLatin1String( "int" ) || typeName == QLatin1String( "integer" ) )
138  {
139  type = QVariant::Int;
140  typeName = QStringLiteral( "integer" );
141  length = -1;
142  }
143  else if ( typeName == QLatin1String( "int8" ) || typeName == QLatin1String( "long" ) )
144  {
145  type = QVariant::LongLong;
146  typeName = QStringLiteral( "int8" );
147  length = -1;
148  }
149  else if ( typeName == QLatin1String( "real" ) || typeName == QLatin1String( "double" ) )
150  {
151  type = QVariant::Double;
152  typeName = QStringLiteral( "double" );
153  length = 20;
154  precision = 5;
155  }
156  else if ( typeName == QLatin1String( "date" ) )
157  {
158  type = QVariant::Date;
159  typeName = QStringLiteral( "date" );
160  length = -1;
161  }
162  else if ( typeName == QLatin1String( "time" ) )
163  {
164  type = QVariant::Time;
165  typeName = QStringLiteral( "time" );
166  length = -1;
167  }
168  else if ( typeName == QLatin1String( "datetime" ) )
169  {
170  type = QVariant::DateTime;
171  typeName = QStringLiteral( "datetime" );
172  length = -1;
173  }
174  else if ( typeName == QLatin1String( "bool" ) || typeName == QLatin1String( "boolean" ) )
175  {
176  type = QVariant::Bool;
177  typeName = QStringLiteral( "boolean" );
178  length = -1;
179  }
180  else if ( typeName == QLatin1String( "binary" ) )
181  {
182  type = QVariant::ByteArray;
183  typeName = QStringLiteral( "binary" );
184  length = -1;
185  }
186 
187  if ( !reFieldDef.cap( 2 ).isEmpty() )
188  {
189  length = reFieldDef.cap( 2 ).toInt();
190  }
191  if ( !reFieldDef.cap( 3 ).isEmpty() )
192  {
193  precision = reFieldDef.cap( 3 ).toInt();
194  }
195  if ( !reFieldDef.cap( 4 ).isEmpty() )
196  {
197  //array
198  subType = type;
199  type = ( subType == QVariant::String ? QVariant::StringList : QVariant::List );
200  }
201  }
202  if ( !name.isEmpty() )
203  attributes.append( QgsField( name, type, typeName, length, precision, QString(), subType ) );
204  }
205  addAttributes( attributes );
206  }
207 
208  if ( query.hasQueryItem( QStringLiteral( "index" ) ) && query.queryItemValue( QStringLiteral( "index" ) ) == QLatin1String( "yes" ) )
209  {
210  createSpatialIndex();
211  }
212 
213 }
214 
215 QgsMemoryProvider::~QgsMemoryProvider()
216 {
217  delete mSpatialIndex;
218 }
219 
220 QString QgsMemoryProvider::providerKey()
221 {
222  return TEXT_PROVIDER_KEY;
223 }
224 
225 QString QgsMemoryProvider::providerDescription()
226 {
227  return TEXT_PROVIDER_DESCRIPTION;
228 }
229 
230 QgsMemoryProvider *QgsMemoryProvider::createProvider( const QString &uri,
231  const ProviderOptions &options,
232  QgsDataProvider::ReadFlags flags )
233 {
234  return new QgsMemoryProvider( uri, options, flags );
235 }
236 
237 QgsAbstractFeatureSource *QgsMemoryProvider::featureSource() const
238 {
239  return new QgsMemoryFeatureSource( this );
240 }
241 
242 QString QgsMemoryProvider::dataSourceUri( bool expandAuthConfig ) const
243 {
244  Q_UNUSED( expandAuthConfig )
245 
246  QUrl uri( QStringLiteral( "memory" ) );
247  QUrlQuery query;
248  QString geometry = QgsWkbTypes::displayString( mWkbType );
249  query.addQueryItem( QStringLiteral( "geometry" ), geometry );
250 
251  if ( mCrs.isValid() )
252  {
253  QString crsDef;
254  QString authid = mCrs.authid();
255  if ( authid.startsWith( QLatin1String( "EPSG:" ) ) )
256  {
257  crsDef = authid;
258  }
259  else
260  {
261  crsDef = QStringLiteral( "wkt:%1" ).arg( mCrs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) );
262  }
263  query.addQueryItem( QStringLiteral( "crs" ), crsDef );
264  }
265  if ( mSpatialIndex )
266  {
267  query.addQueryItem( QStringLiteral( "index" ), QStringLiteral( "yes" ) );
268  }
269 
270  QgsAttributeList attrs = const_cast<QgsMemoryProvider *>( this )->attributeIndexes();
271  for ( int i = 0; i < attrs.size(); i++ )
272  {
273  QgsField field = mFields.at( attrs[i] );
274  QString fieldDef = field.name();
275  fieldDef.append( QStringLiteral( ":%2(%3,%4)" ).arg( field.typeName() ).arg( field.length() ).arg( field.precision() ) );
276  query.addQueryItem( QStringLiteral( "field" ), fieldDef );
277  }
278  uri.setQuery( query );
279 
280  return QString( uri.toEncoded() );
281 
282 }
283 
284 QString QgsMemoryProvider::storageType() const
285 {
286  return QStringLiteral( "Memory storage" );
287 }
288 
289 QgsFeatureIterator QgsMemoryProvider::getFeatures( const QgsFeatureRequest &request ) const
290 {
291  return QgsFeatureIterator( new QgsMemoryFeatureIterator( new QgsMemoryFeatureSource( this ), true, request ) );
292 }
293 
294 
295 QgsRectangle QgsMemoryProvider::extent() const
296 {
297  if ( mExtent.isEmpty() && !mFeatures.isEmpty() )
298  {
299  mExtent.setMinimal();
300  if ( mSubsetString.isEmpty() )
301  {
302  // fast way - iterate through all features
303  const auto constMFeatures = mFeatures;
304  for ( const QgsFeature &feat : constMFeatures )
305  {
306  if ( feat.hasGeometry() )
307  mExtent.combineExtentWith( feat.geometry().boundingBox() );
308  }
309  }
310  else
311  {
312  QgsFeature f;
313  QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setNoAttributes() );
314  while ( fi.nextFeature( f ) )
315  {
316  if ( f.hasGeometry() )
317  mExtent.combineExtentWith( f.geometry().boundingBox() );
318  }
319  }
320  }
321  else if ( mFeatures.isEmpty() )
322  {
323  mExtent.setMinimal();
324  }
325 
326  return mExtent;
327 }
328 
329 QgsWkbTypes::Type QgsMemoryProvider::wkbType() const
330 {
331  return mWkbType;
332 }
333 
334 long QgsMemoryProvider::featureCount() const
335 {
336  if ( mSubsetString.isEmpty() )
337  return mFeatures.count();
338 
339  // subset string set, no alternative but testing each feature
340  QgsFeatureIterator fit = QgsFeatureIterator( new QgsMemoryFeatureIterator( new QgsMemoryFeatureSource( this ), true, QgsFeatureRequest().setNoAttributes() ) );
341  int count = 0;
342  QgsFeature feature;
343  while ( fit.nextFeature( feature ) )
344  {
345  count++;
346  }
347  return count;
348 }
349 
350 QgsFields QgsMemoryProvider::fields() const
351 {
352  return mFields;
353 }
354 
355 bool QgsMemoryProvider::isValid() const
356 {
357  return ( mWkbType != QgsWkbTypes::Unknown );
358 }
359 
361 {
362  // TODO: make provider projection-aware
363  return mCrs; // return default CRS
364 }
365 
366 void QgsMemoryProvider::handlePostCloneOperations( QgsVectorDataProvider *source )
367 {
368  if ( QgsMemoryProvider *other = qobject_cast< QgsMemoryProvider * >( source ) )
369  {
370  // these properties aren't copied when cloning a memory provider by uri, so we need to do it manually
371  mFeatures = other->mFeatures;
372  mNextFeatureId = other->mNextFeatureId;
373  mExtent = other->mExtent;
374  }
375 }
376 
377 // returns TRUE if all features were added successfully, or FALSE if any feature could not be added
378 bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist, Flags flags )
379 {
380  bool result = true;
381  // whether or not to update the layer extent on the fly as we add features
382  bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
383 
384  int fieldCount = mFields.count();
385 
386  // For rollback
387  const auto oldExtent { mExtent };
388  const auto oldNextFeatureId { mNextFeatureId };
389  QgsFeatureIds addedFids ;
390 
391  for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end() && result ; ++it )
392  {
393  it->setId( mNextFeatureId );
394  it->setValid( true );
395  if ( it->attributes().count() < fieldCount )
396  {
397  // ensure features have the correct number of attributes by padding
398  // them with null attributes for missing values
399  QgsAttributes attributes = it->attributes();
400  for ( int i = it->attributes().count(); i < mFields.count(); ++i )
401  {
402  attributes.append( QVariant( mFields.at( i ).type() ) );
403  }
404  it->setAttributes( attributes );
405  }
406  else if ( it->attributes().count() > fieldCount )
407  {
408  // too many attributes
409  pushError( tr( "Feature has too many attributes (expecting %1, received %2)" ).arg( fieldCount ).arg( it->attributes().count() ) );
410  QgsAttributes attributes = it->attributes();
411  attributes.resize( mFields.count() );
412  it->setAttributes( attributes );
413  }
414 
415  if ( it->hasGeometry() && mWkbType == QgsWkbTypes::NoGeometry )
416  {
417  it->clearGeometry();
418  }
419  else if ( it->hasGeometry() && QgsWkbTypes::geometryType( it->geometry().wkbType() ) !=
420  QgsWkbTypes::geometryType( mWkbType ) )
421  {
422  pushError( tr( "Could not add feature with geometry type %1 to layer of type %2" ).arg( QgsWkbTypes::displayString( it->geometry().wkbType() ),
423  QgsWkbTypes::displayString( mWkbType ) ) );
424  result = false;
425  continue;
426  }
427 
428  // Check attribute conversion
429  bool conversionError { false };
430  QString errorMessage;
431  for ( int i = 0; i < mFields.count(); ++i )
432  {
433  QVariant attrValue { it->attribute( i ) };
434  if ( ! attrValue.isNull() && ! mFields.at( i ).convertCompatible( attrValue, &errorMessage ) )
435  {
436  // Push first conversion error only
437  if ( result )
438  {
439  pushError( tr( "Could not store attribute \"%1\": %2" )
440  .arg( mFields.at( i ).name(), errorMessage ) );
441  }
442  result = false;
443  conversionError = true;
444  continue;
445  }
446  }
447 
448  // Skip the feature if there is at least one conversion error
449  if ( conversionError )
450  {
451  if ( flags.testFlag( QgsFeatureSink::Flag::RollBackOnErrors ) )
452  {
453  break;
454  }
455  continue;
456  }
457 
458  mFeatures.insert( mNextFeatureId, *it );
459  addedFids.insert( mNextFeatureId );
460 
461  if ( it->hasGeometry() )
462  {
463  if ( updateExtent )
464  mExtent.combineExtentWith( it->geometry().boundingBox() );
465 
466  // update spatial index
467  if ( mSpatialIndex )
468  mSpatialIndex->addFeature( *it );
469  }
470 
471  mNextFeatureId++;
472  }
473 
474  // Roll back
475  if ( ! result && flags.testFlag( QgsFeatureSink::Flag::RollBackOnErrors ) )
476  {
477  for ( const QgsFeatureId &addedFid : addedFids )
478  {
479  mFeatures.remove( addedFid );
480  }
481  mExtent = oldExtent;
482  mNextFeatureId = oldNextFeatureId;
483  }
484  else
485  {
486  clearMinMaxCache();
487  }
488 
489  return result;
490 }
491 
492 bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds &id )
493 {
494  for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
495  {
496  QgsFeatureMap::iterator fit = mFeatures.find( *it );
497 
498  // check whether such feature exists
499  if ( fit == mFeatures.end() )
500  continue;
501 
502  // update spatial index
503  if ( mSpatialIndex )
504  mSpatialIndex->deleteFeature( *fit );
505 
506  mFeatures.erase( fit );
507  }
508 
509  updateExtents();
510  clearMinMaxCache();
511 
512  return true;
513 }
514 
515 bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
516 {
517  for ( QList<QgsField>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
518  {
519  switch ( it->type() )
520  {
521  case QVariant::Int:
522  case QVariant::Double:
523  case QVariant::String:
524  case QVariant::Date:
525  case QVariant::Time:
526  case QVariant::DateTime:
527  case QVariant::LongLong:
528  case QVariant::StringList:
529  case QVariant::List:
530  case QVariant::Bool:
531  case QVariant::ByteArray:
532  break;
533  default:
534  QgsDebugMsg( "Field type not supported: " + it->typeName() );
535  continue;
536  }
537  // add new field as a last one
538  mFields.append( *it );
539 
540  for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
541  {
542  QgsFeature &f = fit.value();
543  QgsAttributes attr = f.attributes();
544  attr.append( QVariant() );
545  f.setAttributes( attr );
546  }
547  }
548  return true;
549 }
550 
551 bool QgsMemoryProvider::renameAttributes( const QgsFieldNameMap &renamedAttributes )
552 {
553  QgsFieldNameMap::const_iterator renameIt = renamedAttributes.constBegin();
554  bool result = true;
555  for ( ; renameIt != renamedAttributes.constEnd(); ++renameIt )
556  {
557  int fieldIndex = renameIt.key();
558  if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
559  {
560  result = false;
561  continue;
562  }
563  if ( mFields.indexFromName( renameIt.value() ) >= 0 )
564  {
565  //field name already in use
566  result = false;
567  continue;
568  }
569 
570  mFields.rename( fieldIndex, renameIt.value() );
571  }
572  return result;
573 }
574 
575 bool QgsMemoryProvider::deleteAttributes( const QgsAttributeIds &attributes )
576 {
577  QList<int> attrIdx = qgis::setToList( attributes );
578  std::sort( attrIdx.begin(), attrIdx.end(), std::greater<int>() );
579 
580  // delete attributes one-by-one with decreasing index
581  for ( QList<int>::const_iterator it = attrIdx.constBegin(); it != attrIdx.constEnd(); ++it )
582  {
583  int idx = *it;
584  mFields.remove( idx );
585 
586  for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
587  {
588  QgsFeature &f = fit.value();
589  QgsAttributes attr = f.attributes();
590  attr.remove( idx );
591  f.setAttributes( attr );
592  }
593  }
594  clearMinMaxCache();
595  return true;
596 }
597 
598 bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_map )
599 {
600  bool result { true };
601 
602  QgsChangedAttributesMap rollBackMap;
603 
604  QString errorMessage;
605  for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
606  {
607  QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
608  if ( fit == mFeatures.end() )
609  continue;
610 
611  const QgsAttributeMap &attrs = it.value();
612  QgsAttributeMap rollBackAttrs;
613 
614  // Break on errors
615  for ( QgsAttributeMap::const_iterator it2 = attrs.constBegin(); it2 != attrs.constEnd(); ++it2 )
616  {
617  QVariant attrValue { it2.value() };
618  // Check attribute conversion
619  const bool conversionError { ! attrValue.isNull()
620  && ! mFields.at( it2.key() ).convertCompatible( attrValue, &errorMessage ) };
621  if ( conversionError )
622  {
623  // Push first conversion error only
624  if ( result )
625  {
626  pushError( tr( "Could not change attribute %1 having type %2 for feature %4: %3" )
627  .arg( mFields.at( it2.key() ).name(), it2.value( ).typeName(),
628  errorMessage ).arg( it.key() ) );
629  }
630  result = false;
631  break;
632  }
633  rollBackAttrs.insert( it2.key(), fit->attribute( it2.key() ) );
634  fit->setAttribute( it2.key(), it2.value() );
635  }
636  rollBackMap.insert( it.key(), rollBackAttrs );
637  }
638 
639  // Roll back
640  if ( ! result )
641  {
642  changeAttributeValues( rollBackMap );
643  }
644  else
645  {
646  clearMinMaxCache();
647  }
648  return result;
649 }
650 
651 bool QgsMemoryProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
652 {
653  for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
654  {
655  QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
656  if ( fit == mFeatures.end() )
657  continue;
658 
659  // update spatial index
660  if ( mSpatialIndex )
661  mSpatialIndex->deleteFeature( *fit );
662 
663  fit->setGeometry( it.value() );
664 
665  // update spatial index
666  if ( mSpatialIndex )
667  mSpatialIndex->addFeature( *fit );
668  }
669 
670  updateExtents();
671 
672  return true;
673 }
674 
675 QString QgsMemoryProvider::subsetString() const
676 {
677  return mSubsetString;
678 }
679 
680 bool QgsMemoryProvider::setSubsetString( const QString &theSQL, bool updateFeatureCount )
681 {
682  Q_UNUSED( updateFeatureCount )
683 
684  if ( !theSQL.isEmpty() )
685  {
686  QgsExpression tempExpression( theSQL );
687  if ( tempExpression.hasParserError() )
688  return false;
689  }
690 
691  if ( theSQL == mSubsetString )
692  return true;
693 
694  mSubsetString = theSQL;
695  clearMinMaxCache();
696  mExtent.setMinimal();
697 
698  emit dataChanged();
699  return true;
700 }
701 
702 bool QgsMemoryProvider::createSpatialIndex()
703 {
704  if ( !mSpatialIndex )
705  {
706  mSpatialIndex = new QgsSpatialIndex();
707 
708  // add existing features to index
709  for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
710  {
711  mSpatialIndex->addFeature( *it );
712  }
713  }
714  return true;
715 }
716 
717 QgsFeatureSource::SpatialIndexPresence QgsMemoryProvider::hasSpatialIndex() const
718 {
719  return mSpatialIndex ? SpatialIndexPresent : SpatialIndexNotPresent;
720 }
721 
722 QgsVectorDataProvider::Capabilities QgsMemoryProvider::capabilities() const
723 {
724  return AddFeatures | DeleteFeatures | ChangeGeometries |
725  ChangeAttributeValues | AddAttributes | DeleteAttributes | RenameAttributes | CreateSpatialIndex |
726  SelectAtId | CircularGeometries | FastTruncate;
727 }
728 
729 bool QgsMemoryProvider::truncate()
730 {
731  mFeatures.clear();
732  clearMinMaxCache();
733  mExtent.setMinimal();
734  return true;
735 }
736 
737 void QgsMemoryProvider::updateExtents()
738 {
739  mExtent.setMinimal();
740 }
741 
742 QString QgsMemoryProvider::name() const
743 {
744  return TEXT_PROVIDER_KEY;
745 }
746 
747 QString QgsMemoryProvider::description() const
748 {
749  return TEXT_PROVIDER_DESCRIPTION;
750 }
751 
qgsfields.h
QgsAttributeIds
QSet< int > QgsAttributeIds
Definition: qgsvectordataprovider.h:39
QgsWkbTypes::displayString
static QString displayString(Type type) SIP_HOLDGIL
Returns a display string type for a WKB type, e.g., the geometry name used in WKT geometry representa...
Definition: qgswkbtypes.cpp:145
QgsField::length
int length
Definition: qgsfield.h:55
QgsCoordinateReferenceSystem::WKT_PREFERRED
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
Definition: qgscoordinatereferencesystem.h:679
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:51
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:45
qgsfeature.h
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:67
qgsmemoryprovider.h
QgsRectangle::setMinimal
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:151
QgsField::typeName
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:138
qgsmemoryfeatureiterator.h
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
QgsChangedAttributesMap
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:569
field
const QgsField & field
Definition: qgsfield.h:456
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsVectorDataProvider::NativeType
Definition: qgsvectordataprovider.h:462
QgsAttributeList
QList< int > QgsAttributeList
Definition: qgsfield.h:26
QgsField::name
QString name
Definition: qgsfield.h:59
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsWkbTypes::parseType
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
QgsField::precision
int precision
Definition: qgsfield.h:56
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:76
precision
int precision
Definition: qgswfsgetfeature.cpp:49
QgsWkbTypes::Unknown
@ Unknown
Definition: qgswkbtypes.h:71
QgsFeatureSource::SpatialIndexPresence
SpatialIndexPresence
Enumeration of spatial index presence states.
Definition: qgsfeaturesource.h:188
QgsAbstractFeatureSource
Base class that can be used for any class that is capable of returning features.
Definition: qgsfeaturerequest.h:743
QgsFeatureList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:583
QgsAttributeMap
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QgsSpatialIndex
A spatial index for QgsFeature objects.
Definition: qgsspatialindex.h:68
typeName
const QString & typeName
Definition: qgswfsgetfeature.cpp:55
QgsFeatureIds
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
QgsFeature::attributes
QgsAttributes attributes
Definition: qgsfeature.h:65
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:206
QgsWkbTypes::NoGeometry
@ NoGeometry
Definition: qgswkbtypes.h:85
qgsgeometry.h
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:374
QgsFeature::hasGeometry
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:199
QgsFieldNameMap
QMap< int, QString > QgsFieldNameMap
Definition: qgsattributes.h:44
QgsWkbTypes::geometryType
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...
Definition: qgswkbtypes.h:938
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:996
QgsAttributes
A vector of attributes.
Definition: qgsattributes.h:58
QgsGeometryMap
QMap< QgsFeatureId, QgsGeometry > QgsGeometryMap
Definition: qgsfeature.h:578
qgsspatialindex.h
QgsVectorDataProvider
This is the base class for vector data providers.
Definition: qgsvectordataprovider.h:59
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
qgslogger.h
QgsFeature::setAttributes
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:129
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:105
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:265
qgscoordinatereferencesystem.h
attributeIndexes
const QgsAttributeList & attributeIndexes
Definition: qgswfsgetfeature.cpp:53
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50