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 >()
113 if ( query.hasQueryItem( QStringLiteral(
"field" ) ) )
115 QList<QgsField> attributes;
116 QRegExp reFieldDef(
"\\:"
117 "(int|integer|long|int8|real|double|string|date|time|datetime|binary|bool|boolean)"
121 "$", Qt::CaseInsensitive );
122 QStringList fields = query.allQueryItemValues( QStringLiteral(
"field" ) );
123 for (
int i = 0; i < fields.size(); i++ )
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" ) );
132 int pos = reFieldDef.indexIn( name );
135 name = name.mid( 0, pos );
136 typeName = reFieldDef.cap( 1 ).toLower();
137 if (
typeName == QLatin1String(
"int" ) ||
typeName == QLatin1String(
"integer" ) )
139 type = QVariant::Int;
140 typeName = QStringLiteral(
"integer" );
143 else if (
typeName == QLatin1String(
"int8" ) ||
typeName == QLatin1String(
"long" ) )
145 type = QVariant::LongLong;
146 typeName = QStringLiteral(
"int8" );
149 else if (
typeName == QLatin1String(
"real" ) ||
typeName == QLatin1String(
"double" ) )
151 type = QVariant::Double;
152 typeName = QStringLiteral(
"double" );
156 else if (
typeName == QLatin1String(
"date" ) )
158 type = QVariant::Date;
159 typeName = QStringLiteral(
"date" );
162 else if (
typeName == QLatin1String(
"time" ) )
164 type = QVariant::Time;
165 typeName = QStringLiteral(
"time" );
168 else if (
typeName == QLatin1String(
"datetime" ) )
170 type = QVariant::DateTime;
171 typeName = QStringLiteral(
"datetime" );
174 else if (
typeName == QLatin1String(
"bool" ) ||
typeName == QLatin1String(
"boolean" ) )
176 type = QVariant::Bool;
177 typeName = QStringLiteral(
"boolean" );
180 else if (
typeName == QLatin1String(
"binary" ) )
182 type = QVariant::ByteArray;
183 typeName = QStringLiteral(
"binary" );
187 if ( !reFieldDef.cap( 2 ).isEmpty() )
189 length = reFieldDef.cap( 2 ).toInt();
191 if ( !reFieldDef.cap( 3 ).isEmpty() )
195 if ( !reFieldDef.cap( 4 ).isEmpty() )
199 type = ( subType == QVariant::String ? QVariant::StringList : QVariant::List );
202 if ( !name.isEmpty() )
205 addAttributes( attributes );
208 if ( query.hasQueryItem( QStringLiteral(
"index" ) ) && query.queryItemValue( QStringLiteral(
"index" ) ) == QLatin1String(
"yes" ) )
210 createSpatialIndex();
215 QgsMemoryProvider::~QgsMemoryProvider()
217 delete mSpatialIndex;
220 QString QgsMemoryProvider::providerKey()
222 return TEXT_PROVIDER_KEY;
225 QString QgsMemoryProvider::providerDescription()
227 return TEXT_PROVIDER_DESCRIPTION;
230 QgsMemoryProvider *QgsMemoryProvider::createProvider(
const QString &uri,
231 const ProviderOptions &options,
232 QgsDataProvider::ReadFlags flags )
234 return new QgsMemoryProvider( uri, options, flags );
239 return new QgsMemoryFeatureSource(
this );
242 QString QgsMemoryProvider::dataSourceUri(
bool expandAuthConfig )
const
244 Q_UNUSED( expandAuthConfig )
246 QUrl uri( QStringLiteral(
"memory" ) );
249 query.addQueryItem( QStringLiteral(
"geometry" ), geometry );
251 if ( mCrs.isValid() )
254 QString authid = mCrs.authid();
255 if ( authid.startsWith( QLatin1String(
"EPSG:" ) ) )
263 query.addQueryItem( QStringLiteral(
"crs" ), crsDef );
267 query.addQueryItem( QStringLiteral(
"index" ), QStringLiteral(
"yes" ) );
271 for (
int i = 0; i < attrs.size(); i++ )
276 query.addQueryItem( QStringLiteral(
"field" ), fieldDef );
278 uri.setQuery( query );
280 return QString( uri.toEncoded() );
284 QString QgsMemoryProvider::storageType()
const
286 return QStringLiteral(
"Memory storage" );
291 return QgsFeatureIterator(
new QgsMemoryFeatureIterator(
new QgsMemoryFeatureSource(
this ),
true, request ) );
297 if ( mExtent.isEmpty() && !mFeatures.isEmpty() )
300 if ( mSubsetString.isEmpty() )
303 const auto constMFeatures = mFeatures;
304 for (
const QgsFeature &feat : constMFeatures )
306 if ( feat.hasGeometry() )
307 mExtent.combineExtentWith( feat.geometry().boundingBox() );
321 else if ( mFeatures.isEmpty() )
323 mExtent.setMinimal();
334 long QgsMemoryProvider::featureCount()
const
336 if ( mSubsetString.isEmpty() )
337 return mFeatures.count();
350 QgsFields QgsMemoryProvider::fields()
const
355 bool QgsMemoryProvider::isValid()
const
368 if ( QgsMemoryProvider *other = qobject_cast< QgsMemoryProvider * >( source ) )
371 mFeatures = other->mFeatures;
372 mNextFeatureId = other->mNextFeatureId;
373 mExtent = other->mExtent;
378 bool QgsMemoryProvider::addFeatures(
QgsFeatureList &flist, Flags flags )
382 bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
384 int fieldCount = mFields.count();
387 const auto oldExtent { mExtent };
388 const auto oldNextFeatureId { mNextFeatureId };
391 for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end() && result ; ++it )
393 it->setId( mNextFeatureId );
394 it->setValid(
true );
395 if ( it->attributes().count() < fieldCount )
400 for (
int i = it->attributes().count(); i < mFields.count(); ++i )
402 attributes.append( QVariant( mFields.at( i ).type() ) );
404 it->setAttributes( attributes );
406 else if ( it->attributes().count() > fieldCount )
409 pushError( tr(
"Feature has too many attributes (expecting %1, received %2)" ).arg( fieldCount ).arg( it->attributes().count() ) );
411 attributes.resize( mFields.count() );
412 it->setAttributes( attributes );
422 pushError( tr(
"Could not add feature with geometry type %1 to layer of type %2" ).arg(
QgsWkbTypes::displayString( it->geometry().wkbType() ),
429 bool conversionError {
false };
430 QString errorMessage;
431 for (
int i = 0; i < mFields.count(); ++i )
433 QVariant attrValue { it->attribute( i ) };
434 if ( ! attrValue.isNull() && ! mFields.at( i ).convertCompatible( attrValue, &errorMessage ) )
439 pushError( tr(
"Could not store attribute \"%1\": %2" )
440 .arg( mFields.at( i ).name(), errorMessage ) );
443 conversionError =
true;
449 if ( conversionError )
451 if ( flags.testFlag( QgsFeatureSink::Flag::RollBackOnErrors ) )
458 mFeatures.insert( mNextFeatureId, *it );
459 addedFids.insert( mNextFeatureId );
461 if ( it->hasGeometry() )
464 mExtent.combineExtentWith( it->geometry().boundingBox() );
468 mSpatialIndex->addFeature( *it );
475 if ( ! result && flags.testFlag( QgsFeatureSink::Flag::RollBackOnErrors ) )
479 mFeatures.remove( addedFid );
482 mNextFeatureId = oldNextFeatureId;
492 bool QgsMemoryProvider::deleteFeatures(
const QgsFeatureIds &
id )
494 for ( QgsFeatureIds::const_iterator it =
id.begin(); it !=
id.end(); ++it )
496 QgsFeatureMap::iterator fit = mFeatures.find( *it );
499 if ( fit == mFeatures.end() )
504 mSpatialIndex->deleteFeature( *fit );
506 mFeatures.erase( fit );
515 bool QgsMemoryProvider::addAttributes(
const QList<QgsField> &attributes )
517 for ( QList<QgsField>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
519 switch ( it->type() )
522 case QVariant::Double:
523 case QVariant::String:
526 case QVariant::DateTime:
527 case QVariant::LongLong:
528 case QVariant::StringList:
531 case QVariant::ByteArray:
534 QgsDebugMsg(
"Field type not supported: " + it->typeName() );
538 mFields.append( *it );
540 for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
544 attr.append( QVariant() );
551 bool QgsMemoryProvider::renameAttributes(
const QgsFieldNameMap &renamedAttributes )
553 QgsFieldNameMap::const_iterator renameIt = renamedAttributes.constBegin();
555 for ( ; renameIt != renamedAttributes.constEnd(); ++renameIt )
557 int fieldIndex = renameIt.key();
558 if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
563 if ( mFields.indexFromName( renameIt.value() ) >= 0 )
570 mFields.rename( fieldIndex, renameIt.value() );
575 bool QgsMemoryProvider::deleteAttributes(
const QgsAttributeIds &attributes )
577 QList<int> attrIdx = qgis::setToList( attributes );
578 std::sort( attrIdx.begin(), attrIdx.end(), std::greater<int>() );
581 for ( QList<int>::const_iterator it = attrIdx.constBegin(); it != attrIdx.constEnd(); ++it )
584 mFields.remove( idx );
586 for ( QgsFeatureMap::iterator fit = mFeatures.begin(); fit != mFeatures.end(); ++fit )
600 bool result {
true };
604 QString errorMessage;
605 for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
607 QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
608 if ( fit == mFeatures.end() )
615 for ( QgsAttributeMap::const_iterator it2 = attrs.constBegin(); it2 != attrs.constEnd(); ++it2 )
617 QVariant attrValue { it2.value() };
619 const bool conversionError { ! attrValue.isNull()
620 && ! mFields.at( it2.key() ).convertCompatible( attrValue, &errorMessage ) };
621 if ( conversionError )
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() ) );
633 rollBackAttrs.insert( it2.key(), fit->attribute( it2.key() ) );
634 fit->setAttribute( it2.key(), it2.value() );
636 rollBackMap.insert( it.key(), rollBackAttrs );
642 changeAttributeValues( rollBackMap );
651 bool QgsMemoryProvider::changeGeometryValues(
const QgsGeometryMap &geometry_map )
653 for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
655 QgsFeatureMap::iterator fit = mFeatures.find( it.key() );
656 if ( fit == mFeatures.end() )
661 mSpatialIndex->deleteFeature( *fit );
663 fit->setGeometry( it.value() );
667 mSpatialIndex->addFeature( *fit );
675 QString QgsMemoryProvider::subsetString()
const
677 return mSubsetString;
680 bool QgsMemoryProvider::setSubsetString(
const QString &theSQL,
bool updateFeatureCount )
682 Q_UNUSED( updateFeatureCount )
684 if ( !theSQL.isEmpty() )
687 if ( tempExpression.hasParserError() )
691 if ( theSQL == mSubsetString )
694 mSubsetString = theSQL;
696 mExtent.setMinimal();
702 bool QgsMemoryProvider::createSpatialIndex()
704 if ( !mSpatialIndex )
709 for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it )
711 mSpatialIndex->addFeature( *it );
719 return mSpatialIndex ? SpatialIndexPresent : SpatialIndexNotPresent;
722 QgsVectorDataProvider::Capabilities QgsMemoryProvider::capabilities()
const
724 return AddFeatures | DeleteFeatures | ChangeGeometries |
725 ChangeAttributeValues | AddAttributes | DeleteAttributes | RenameAttributes | CreateSpatialIndex |
726 SelectAtId | CircularGeometries | FastTruncate;
729 bool QgsMemoryProvider::truncate()
733 mExtent.setMinimal();
737 void QgsMemoryProvider::updateExtents()
739 mExtent.setMinimal();
742 QString QgsMemoryProvider::name()
const
744 return TEXT_PROVIDER_KEY;
747 QString QgsMemoryProvider::description()
const
749 return TEXT_PROVIDER_DESCRIPTION;