Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsogrfeatureiterator.cpp
3 : : ---------------------
4 : : begin : Juli 2012
5 : : copyright : (C) 2012 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 : : #include "qgsogrfeatureiterator.h"
16 : :
17 : : #include "qgsogrprovider.h"
18 : : #include "qgsogrexpressioncompiler.h"
19 : : #include "qgssqliteexpressioncompiler.h"
20 : :
21 : : #include "qgscplhttpfetchoverrider.h"
22 : : #include "qgsogrutils.h"
23 : : #include "qgsapplication.h"
24 : : #include "qgsgeometry.h"
25 : : #include "qgslogger.h"
26 : : #include "qgsmessagelog.h"
27 : : #include "qgssettings.h"
28 : : #include "qgsexception.h"
29 : : #include "qgswkbtypes.h"
30 : : #include "qgsogrtransaction.h"
31 : :
32 : : #include <QTextCodec>
33 : : #include <QFile>
34 : :
35 : : // using from provider:
36 : : // - setRelevantFields(), mRelevantFieldsForNextFeature
37 : : // - ogrLayer
38 : : // - mFetchFeaturesWithoutGeom
39 : : // - mAttributeFields
40 : : // - mEncoding
41 : :
42 : : ///@cond PRIVATE
43 : :
44 : :
45 : 92 : QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource *source, bool ownSource, const QgsFeatureRequest &request, QgsTransaction *transaction )
46 : 92 : : QgsAbstractFeatureIteratorFromSource<QgsOgrFeatureSource>( source, ownSource, request )
47 : 92 : , mSharedDS( source->mSharedDS )
48 : 92 : , mFirstFieldIsFid( source->mFirstFieldIsFid )
49 : 92 : , mFieldsWithoutFid( source->mFieldsWithoutFid )
50 : 92 : , mAuthCfg( source->mAuthCfg )
51 : 92 : , mSymbolType( QgsSymbol::symbolTypeForGeometryType( QgsWkbTypes::geometryType( source->mWkbType ) ) )
52 : 184 : {
53 : :
54 : : /* When inside a transaction for GPKG/SQLite and fetching fid(s) we might be nested inside an outer fetching loop,
55 : : * (see GH #39178) so we need to skip all calls that might reset the reading (rewind) to avoid an endless loop in the
56 : : * outer fetching iterator that uses the same connection.
57 : : */
58 : 92 : mAllowResetReading = ! transaction ||
59 : 0 : ( source->mDriverName != QLatin1String( "GPKG" ) && source->mDriverName != QLatin1String( "SQLite" ) ) ||
60 : 133 : ( mRequest.filterType() != QgsFeatureRequest::FilterType::FilterFid
61 : 0 : && mRequest.filterType() != QgsFeatureRequest::FilterType::FilterFids );
62 : :
63 : 92 : QgsCPLHTTPFetchOverrider oCPLHTTPFetcher( mAuthCfg );
64 : 184 : QgsSetCPLHTTPFetchOverriderInitiatorClass( oCPLHTTPFetcher, QStringLiteral( "QgsOgrFeatureIterator" ) )
65 : :
66 : 112 : for ( const auto &id : mRequest.filterFids() )
67 : : {
68 : 20 : mFilterFids.insert( id );
69 : : }
70 : 92 : mFilterFidsIt = mFilterFids.begin();
71 : :
72 : : // Since connection timeout for OGR connections is problematic and can lead to crashes, disable for now.
73 : 92 : mRequest.setTimeout( -1 );
74 : 92 : if ( mSharedDS )
75 : : {
76 : 0 : mOgrLayer = mSharedDS->getLayerFromNameOrIndex( mSource->mLayerName, mSource->mLayerIndex );
77 : 0 : if ( !mOgrLayer )
78 : : {
79 : 0 : return;
80 : : }
81 : 0 : }
82 : : else
83 : : {
84 : : //QgsDebugMsg( "Feature iterator of " + mSource->mLayerName + ": acquiring connection");
85 : 92 : mConn = QgsOgrConnPool::instance()->acquireConnection( QgsOgrProviderUtils::connectionPoolId( mSource->mDataSource, mSource->mShareSameDatasetAmongLayers ), mRequest.timeout(), mRequest.requestMayBeNested() );
86 : 92 : if ( !mConn || !mConn->ds )
87 : : {
88 : 0 : return;
89 : : }
90 : 92 :
91 : 184 : if ( mSource->mLayerName.isNull() )
92 : 92 : {
93 : 92 : mOgrLayer = GDALDatasetGetLayer( mConn->ds, mSource->mLayerIndex );
94 : 92 : }
95 : 92 : else
96 : : {
97 : 92 : mOgrLayer = GDALDatasetGetLayerByName( mConn->ds, mSource->mLayerName.toUtf8().constData() );
98 : : }
99 : 92 : if ( !mOgrLayer )
100 : : {
101 : 0 : return;
102 : : }
103 : :
104 : 92 : if ( mAllowResetReading && !mSource->mSubsetString.isEmpty() )
105 : : {
106 : 0 : mOgrLayerOri = mOgrLayer;
107 : 0 : mOgrLayer = QgsOgrProviderUtils::setSubsetString( mOgrLayer, mConn->ds, mSource->mEncoding, mSource->mSubsetString );
108 : : // If the mSubsetString was a full SELECT ...., then mOgrLayer will be a OGR SQL layer != mOgrLayerOri
109 : :
110 : 92 : mFieldsWithoutFid.clear();
111 : 0 : for ( int i = ( mFirstFieldIsFid ) ? 1 : 0; i < mSource->mFields.size(); i++ )
112 : 0 : mFieldsWithoutFid.append( mSource->mFields.at( i ) );
113 : :
114 : 0 : if ( !mOgrLayer )
115 : : {
116 : 0 : close();
117 : 92 : return;
118 : : }
119 : 0 : }
120 : : }
121 : 92 : QMutexLocker locker( mSharedDS ? &mSharedDS->mutex() : nullptr );
122 : :
123 : 92 : if ( mRequest.destinationCrs().isValid() && mRequest.destinationCrs() != mSource->mCrs )
124 : : {
125 : 0 : mTransform = QgsCoordinateTransform( mSource->mCrs, mRequest.destinationCrs(), mRequest.transformContext() );
126 : 0 : }
127 : : try
128 : : {
129 : 92 : mFilterRect = filterRectToSourceCrs( mTransform );
130 : 92 : }
131 : : catch ( QgsCsException & )
132 : : {
133 : : // can't reproject mFilterRect
134 : 0 : close();
135 : : return;
136 : 0 : }
137 : :
138 : 184 : mFetchGeometry = ( !mFilterRect.isNull() ) ||
139 : 92 : !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ||
140 : 0 : ( mSource->mOgrGeometryTypeFilter != wkbUnknown );
141 : :
142 : 92 : QgsAttributeList attrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) ? mRequest.subsetOfAttributes() : mSource->mFields.allAttributesList();
143 : :
144 : : // ensure that all attributes required for expression filter are being fetched
145 : 92 : if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && request.filterType() == QgsFeatureRequest::FilterExpression )
146 : : {
147 : : //ensure that all fields required for filter expressions are prepared
148 : 0 : QSet<int> attributeIndexes = request.filterExpression()->referencedAttributeIndexes( mSource->mFields );
149 : 0 : attributeIndexes += qgis::listToSet( attrs );
150 : 0 : attrs = qgis::setToList( attributeIndexes );
151 : 0 : mRequest.setSubsetOfAttributes( attrs );
152 : 0 : }
153 : : // also need attributes required by order by
154 : 92 : if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() )
155 : : {
156 : 0 : QSet<int> attributeIndexes;
157 : 0 : const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
158 : 0 : attributeIndexes.reserve( usedAttributeIndices.size() );
159 : 0 : for ( int attrIdx : usedAttributeIndices )
160 : : {
161 : 0 : attributeIndexes << attrIdx;
162 : : }
163 : 0 : attributeIndexes += qgis::listToSet( attrs );
164 : 0 : attrs = qgis::setToList( attributeIndexes );
165 : 0 : mRequest.setSubsetOfAttributes( attrs );
166 : 0 : }
167 : :
168 : 92 : if ( request.filterType() == QgsFeatureRequest::FilterExpression && request.filterExpression()->needsGeometry() )
169 : : {
170 : 0 : mFetchGeometry = true;
171 : 0 : }
172 : :
173 : : // make sure we fetch just relevant fields
174 : : // unless it's a VRT data source filtered by geometry as we don't know which
175 : : // attributes make up the geometry and OGR won't fetch them to evaluate the
176 : : // filter if we choose to ignore them (fixes #11223)
177 : 92 : if ( ( mSource->mDriverName != QLatin1String( "VRT" ) && mSource->mDriverName != QLatin1String( "OGR_VRT" ) ) || mFilterRect.isNull() )
178 : : {
179 : 92 : QgsOgrProviderUtils::setRelevantFields( mOgrLayer, mSource->mFields.count(), mFetchGeometry, attrs, mSource->mFirstFieldIsFid, mSource->mSubsetString );
180 : 92 : if ( mOgrLayerOri && mOgrLayerOri != mOgrLayer )
181 : 0 : QgsOgrProviderUtils::setRelevantFields( mOgrLayerOri, mSource->mFields.count(), mFetchGeometry, attrs, mSource->mFirstFieldIsFid, mSource->mSubsetString );
182 : 92 : }
183 : :
184 : : // spatial query to select features
185 : 92 : if ( mAllowResetReading )
186 : : {
187 : 92 : if ( !mFilterRect.isNull() )
188 : : {
189 : 0 : OGR_L_SetSpatialFilterRect( mOgrLayer, mFilterRect.xMinimum(), mFilterRect.yMinimum(), mFilterRect.xMaximum(), mFilterRect.yMaximum() );
190 : 0 : if ( mOgrLayerOri && mOgrLayerOri != mOgrLayer )
191 : 0 : OGR_L_SetSpatialFilterRect( mOgrLayerOri, mFilterRect.xMinimum(), mFilterRect.yMinimum(), mFilterRect.xMaximum(), mFilterRect.yMaximum() );
192 : 0 : }
193 : : else
194 : : {
195 : 92 : OGR_L_SetSpatialFilter( mOgrLayer, nullptr );
196 : 92 : if ( mOgrLayerOri && mOgrLayerOri != mOgrLayer )
197 : 0 : OGR_L_SetSpatialFilter( mOgrLayerOri, nullptr );
198 : : }
199 : 92 : }
200 : :
201 : 92 : if ( request.filterType() == QgsFeatureRequest::FilterExpression )
202 : : {
203 : 0 : QgsSqlExpressionCompiler *compiler = nullptr;
204 : 0 : if ( source->mDriverName == QLatin1String( "SQLite" ) || source->mDriverName == QLatin1String( "GPKG" ) )
205 : : {
206 : 0 : compiler = new QgsSQLiteExpressionCompiler( source->mFields, request.flags() & QgsFeatureRequest::IgnoreStaticNodesDuringExpressionCompilation );
207 : 0 : }
208 : : else
209 : : {
210 : 0 : compiler = new QgsOgrExpressionCompiler( source, request.flags() & QgsFeatureRequest::IgnoreStaticNodesDuringExpressionCompilation );
211 : : }
212 : :
213 : 0 : QgsSqlExpressionCompiler::Result result = compiler->compile( request.filterExpression() );
214 : 0 : if ( result == QgsSqlExpressionCompiler::Complete || result == QgsSqlExpressionCompiler::Partial )
215 : : {
216 : 0 : QString whereClause = compiler->result();
217 : 0 : if ( !mSource->mSubsetString.isEmpty() && mOgrLayer == mOgrLayerOri )
218 : : {
219 : 0 : whereClause = QStringLiteral( "(" ) + mSource->mSubsetString +
220 : 0 : QStringLiteral( ") AND (" ) + whereClause +
221 : 0 : QStringLiteral( ")" );
222 : 0 : }
223 : :
224 : 0 : if ( mAllowResetReading )
225 : : {
226 : 0 : if ( OGR_L_SetAttributeFilter( mOgrLayer, mSource->mEncoding->fromUnicode( whereClause ).constData() ) == OGRERR_NONE )
227 : : {
228 : : //if only partial success when compiling expression, we need to double-check results using QGIS' expressions
229 : 0 : mExpressionCompiled = ( result == QgsSqlExpressionCompiler::Complete );
230 : 0 : mCompileStatus = ( mExpressionCompiled ? Compiled : PartiallyCompiled );
231 : 0 : }
232 : 0 : else if ( !mSource->mSubsetString.isEmpty() )
233 : : {
234 : : // OGR rejected the compiled expression. Make sure we restore the original subset string if set (and do the filtering on QGIS' side)
235 : 0 : OGR_L_SetAttributeFilter( mOgrLayer, mSource->mEncoding->fromUnicode( mSource->mSubsetString ).constData() );
236 : 0 : }
237 : 0 : }
238 : :
239 : 0 : }
240 : 0 : else if ( mSource->mSubsetString.isEmpty() && mAllowResetReading )
241 : : {
242 : 0 : OGR_L_SetAttributeFilter( mOgrLayer, nullptr );
243 : 0 : }
244 : :
245 : 0 : delete compiler;
246 : 0 : }
247 : 92 : else if ( mSource->mSubsetString.isEmpty() && mAllowResetReading )
248 : : {
249 : 92 : OGR_L_SetAttributeFilter( mOgrLayer, nullptr );
250 : 92 : }
251 : :
252 : : //start with first feature
253 : 92 : rewind();
254 : :
255 : 92 : }
256 : :
257 : 184 : QgsOgrFeatureIterator::~QgsOgrFeatureIterator()
258 : 184 : {
259 : 92 : close();
260 : 184 : }
261 : :
262 : 0 : bool QgsOgrFeatureIterator::nextFeatureFilterExpression( QgsFeature &f )
263 : : {
264 : 0 : if ( !mExpressionCompiled )
265 : 0 : return QgsAbstractFeatureIterator::nextFeatureFilterExpression( f );
266 : : else
267 : 0 : return fetchFeature( f );
268 : 0 : }
269 : :
270 : 38 : bool QgsOgrFeatureIterator::fetchFeatureWithId( QgsFeatureId id, QgsFeature &feature ) const
271 : : {
272 : 38 : feature.setValid( false );
273 : 38 : gdal::ogr_feature_unique_ptr fet;
274 : :
275 : 38 : if ( mAllowResetReading && !QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( mSource->mDriverName ) )
276 : : {
277 : : OGRLayerH nextFeatureBelongingLayer;
278 : 0 : bool found = false;
279 : : // First pass: try to read from the last feature, in the hope the dataset
280 : : // returns them in increasing feature id number (and as we use a std::set
281 : : // for mFilterFids, we get them in increasing number by the iterator)
282 : : // Second pass: reset before reading
283 : 0 : for ( int passNumber = 0; passNumber < 2; passNumber++ )
284 : : {
285 : 0 : while ( fet.reset( GDALDatasetGetNextFeature(
286 : 0 : mConn->ds, &nextFeatureBelongingLayer, nullptr, nullptr, nullptr ) ), fet )
287 : : {
288 : 0 : if ( nextFeatureBelongingLayer == mOgrLayer )
289 : : {
290 : 0 : if ( OGR_F_GetFID( fet.get() ) == FID_TO_NUMBER( id ) )
291 : : {
292 : 0 : found = true;
293 : 0 : break;
294 : : }
295 : 0 : }
296 : : }
297 : 0 : if ( found || passNumber == 1 )
298 : : {
299 : 0 : break;
300 : : }
301 : 0 : GDALDatasetResetReading( mConn->ds );
302 : 0 : }
303 : :
304 : 0 : if ( !found )
305 : : {
306 : 0 : return false;
307 : : }
308 : 0 : }
309 : : else
310 : : {
311 : 38 : fet.reset( OGR_L_GetFeature( mOgrLayer, FID_TO_NUMBER( id ) ) );
312 : : }
313 : :
314 : 38 : if ( !fet )
315 : : {
316 : 8 : return false;
317 : : }
318 : :
319 : 30 : if ( !readFeature( std::move( fet ), feature ) )
320 : 0 : return false;
321 : :
322 : 30 : feature.setValid( true );
323 : 30 : geometryToDestinationCrs( feature, mTransform );
324 : 30 : return true;
325 : 38 : }
326 : :
327 : 1071 : bool QgsOgrFeatureIterator::checkFeature( gdal::ogr_feature_unique_ptr &fet, QgsFeature &feature )
328 : : {
329 : 1071 : if ( !readFeature( std::move( fet ), feature ) )
330 : 0 : return false;
331 : :
332 : 1071 : if ( !mFilterRect.isNull() && ( !feature.hasGeometry() || feature.geometry().isEmpty() ) )
333 : 0 : return false;
334 : :
335 : : // we have a feature, end this cycle
336 : 1071 : feature.setValid( true );
337 : 1071 : geometryToDestinationCrs( feature, mTransform );
338 : 1071 : return true;
339 : 1071 : }
340 : :
341 : 0 : void QgsOgrFeatureIterator::setInterruptionChecker( QgsFeedback *interruptionChecker )
342 : : {
343 : 0 : mInterruptionChecker = interruptionChecker;
344 : 0 : }
345 : :
346 : 1176 : bool QgsOgrFeatureIterator::fetchFeature( QgsFeature &feature )
347 : : {
348 : 1176 : QMutexLocker locker( mSharedDS ? &mSharedDS->mutex() : nullptr );
349 : :
350 : 1176 : QgsCPLHTTPFetchOverrider oCPLHTTPFetcher( mAuthCfg, mInterruptionChecker );
351 : 2352 : QgsSetCPLHTTPFetchOverriderInitiatorClass( oCPLHTTPFetcher, QStringLiteral( "QgsOgrFeatureIterator" ) )
352 : :
353 : 1176 : feature.setValid( false );
354 : :
355 : 1176 : if ( mClosed || !mOgrLayer )
356 : 0 : return false;
357 : :
358 : 1176 : if ( mRequest.filterType() == QgsFeatureRequest::FilterFid )
359 : : {
360 : 23 : bool result = fetchFeatureWithId( mRequest.filterFid(), feature );
361 : 23 : close(); // the feature has been read or was not found: we have finished here
362 : 23 : return result;
363 : : }
364 : 1153 : else if ( mRequest.filterType() == QgsFeatureRequest::FilterFids )
365 : : {
366 : 17 : while ( mFilterFidsIt != mFilterFids.end() )
367 : : {
368 : 15 : QgsFeatureId nextId = *mFilterFidsIt;
369 : 15 : ++mFilterFidsIt;
370 : :
371 : 15 : if ( fetchFeatureWithId( nextId, feature ) )
372 : 15 : return true;
373 : : }
374 : 2 : close();
375 : 2 : return false;
376 : : }
377 : :
378 : 1136 : gdal::ogr_feature_unique_ptr fet;
379 : :
380 : : // OSM layers (especially large ones) need the GDALDataset::GetNextFeature() call rather than OGRLayer::GetNextFeature()
381 : : // see more details here: https://trac.osgeo.org/gdal/wiki/rfc66_randomlayerreadwrite
382 : 1136 : if ( !QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( mSource->mDriverName ) )
383 : : {
384 : : OGRLayerH nextFeatureBelongingLayer;
385 : 0 : while ( fet.reset( GDALDatasetGetNextFeature( mConn->ds, &nextFeatureBelongingLayer, nullptr, nullptr, nullptr ) ), fet )
386 : : {
387 : 0 : if ( nextFeatureBelongingLayer == mOgrLayer && checkFeature( fet, feature ) )
388 : : {
389 : 0 : return true;
390 : : }
391 : : }
392 : 0 : }
393 : : else
394 : : {
395 : :
396 : 1136 : while ( fet.reset( OGR_L_GetNextFeature( mOgrLayer ) ), fet )
397 : : {
398 : 1071 : if ( checkFeature( fet, feature ) )
399 : : {
400 : 1071 : return true;
401 : : }
402 : : }
403 : : }
404 : :
405 : 65 : close();
406 : 65 : return false;
407 : 1176 : }
408 : :
409 : 184 : void QgsOgrFeatureIterator::resetReading()
410 : : {
411 : 184 : if ( ! mAllowResetReading )
412 : : {
413 : 0 : return;
414 : : }
415 : 184 : if ( !QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( mSource->mDriverName ) )
416 : : {
417 : 0 : GDALDatasetResetReading( mConn->ds );
418 : 0 : }
419 : : else
420 : : {
421 : 184 : OGR_L_ResetReading( mOgrLayer );
422 : : }
423 : 184 : }
424 : :
425 : :
426 : 92 : bool QgsOgrFeatureIterator::rewind()
427 : : {
428 : 92 : QMutexLocker locker( mSharedDS ? &mSharedDS->mutex() : nullptr );
429 : :
430 : 92 : if ( mClosed || !mOgrLayer )
431 : 0 : return false;
432 : :
433 : 92 : resetReading();
434 : :
435 : 92 : mFilterFidsIt = mFilterFids.begin();
436 : :
437 : 92 : return true;
438 : 92 : }
439 : :
440 : :
441 : 250 : bool QgsOgrFeatureIterator::close()
442 : : {
443 : 250 : if ( mSharedDS )
444 : : {
445 : 0 : iteratorClosed();
446 : :
447 : 0 : mOgrLayer = nullptr;
448 : 0 : mSharedDS.reset();
449 : 0 : mClosed = true;
450 : 0 : return true;
451 : : }
452 : :
453 : 250 : if ( !mConn )
454 : 158 : return false;
455 : :
456 : 92 : iteratorClosed();
457 : :
458 : : // Will for example release SQLite3 statements
459 : 92 : if ( mOgrLayer )
460 : : {
461 : 92 : resetReading();
462 : 92 : }
463 : :
464 : 92 : if ( mOgrLayerOri )
465 : : {
466 : 0 : if ( mOgrLayer != mOgrLayerOri )
467 : : {
468 : 0 : GDALDatasetReleaseResultSet( mConn->ds, mOgrLayer );
469 : 0 : }
470 : 0 : mOgrLayer = nullptr;
471 : 0 : mOgrLayerOri = nullptr;
472 : 0 : }
473 : :
474 : 92 : if ( mConn )
475 : : {
476 : : //QgsDebugMsg( "Feature iterator of " + mSource->mLayerName + ": releasing connection");
477 : 92 : QgsOgrConnPool::instance()->releaseConnection( mConn );
478 : 92 : }
479 : :
480 : 92 : mConn = nullptr;
481 : 92 : mOgrLayer = nullptr;
482 : :
483 : 92 : mClosed = true;
484 : 92 : return true;
485 : 250 : }
486 : :
487 : :
488 : 1570 : void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature &f, int attindex ) const
489 : : {
490 : 1570 : if ( mFirstFieldIsFid && attindex == 0 )
491 : : {
492 : 6 : f.setAttribute( 0, static_cast<qint64>( OGR_F_GetFID( ogrFet ) ) );
493 : 6 : return;
494 : : }
495 : :
496 : 1564 : int attindexWithoutFid = ( mFirstFieldIsFid ) ? attindex - 1 : attindex;
497 : 1564 : bool ok = false;
498 : 1564 : QVariant value = QgsOgrUtils::getOgrFeatureAttribute( ogrFet, mFieldsWithoutFid, attindexWithoutFid, mSource->mEncoding, &ok );
499 : 1564 : if ( !ok )
500 : 0 : return;
501 : :
502 : 1564 : f.setAttribute( attindex, value );
503 : 1570 : }
504 : :
505 : 1101 : bool QgsOgrFeatureIterator::readFeature( const gdal::ogr_feature_unique_ptr &fet, QgsFeature &feature ) const
506 : : {
507 : 1101 : feature.setId( OGR_F_GetFID( fet.get() ) );
508 : 1101 : feature.initAttributes( mSource->mFields.count() );
509 : 1101 : feature.setFields( mSource->mFields ); // allow name-based attribute lookups
510 : :
511 : 1101 : bool useIntersect = !mRequest.filterRect().isNull();
512 : 1101 : bool geometryTypeFilter = mSource->mOgrGeometryTypeFilter != wkbUnknown;
513 : 1101 : if ( mFetchGeometry || useIntersect || geometryTypeFilter )
514 : : {
515 : 1101 : OGRGeometryH geom = OGR_F_GetGeometryRef( fet.get() );
516 : :
517 : 1101 : if ( geom )
518 : : {
519 : 1101 : QgsGeometry g = QgsOgrUtils::ogrGeometryToQgsGeometry( geom );
520 : :
521 : : // Insure that multipart datasets return multipart geometry
522 : 1101 : if ( QgsWkbTypes::isMultiType( mSource->mWkbType ) && !g.isMultipart() )
523 : : {
524 : 921 : g.convertToMultiType();
525 : 921 : }
526 : :
527 : 1101 : feature.setGeometry( g );
528 : 1101 : }
529 : : else
530 : 0 : feature.clearGeometry();
531 : :
532 : 1101 : if ( mSource->mOgrGeometryTypeFilter == wkbGeometryCollection &&
533 : 0 : geom && wkbFlatten( OGR_G_GetGeometryType( geom ) ) == wkbGeometryCollection )
534 : : {
535 : : // OK
536 : 0 : }
537 : 2202 : else if ( ( geometryTypeFilter && ( !feature.hasGeometry() || QgsOgrProvider::ogrWkbSingleFlatten( ( OGRwkbGeometryType )feature.geometry().wkbType() ) != mSource->mOgrGeometryTypeFilter ) )
538 : 1101 : || ( useIntersect && ( !feature.hasGeometry()
539 : 0 : || ( mRequest.flags() & QgsFeatureRequest::ExactIntersect && !feature.geometry().intersects( mFilterRect ) )
540 : 0 : || ( !( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) && !feature.geometry().boundingBoxIntersects( mFilterRect ) )
541 : : )
542 : : ) )
543 : : {
544 : 0 : return false;
545 : : }
546 : 1101 : }
547 : :
548 : 1101 : if ( !mFetchGeometry )
549 : : {
550 : 0 : feature.clearGeometry();
551 : 0 : }
552 : :
553 : : // fetch attributes
554 : 1101 : if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
555 : : {
556 : 147 : QgsAttributeList attrs = mRequest.subsetOfAttributes();
557 : 147 : for ( QgsAttributeList::const_iterator it = attrs.constBegin(); it != attrs.constEnd(); ++it )
558 : : {
559 : 0 : getFeatureAttribute( fet.get(), feature, *it );
560 : 0 : }
561 : 147 : }
562 : : else
563 : : {
564 : : // all attributes
565 : 954 : const auto fieldCount = mSource->mFields.count();
566 : 2524 : for ( int idx = 0; idx < fieldCount; ++idx )
567 : : {
568 : 1570 : getFeatureAttribute( fet.get(), feature, idx );
569 : 1570 : }
570 : : }
571 : :
572 : 1101 : if ( mRequest.flags() & QgsFeatureRequest::EmbeddedSymbols )
573 : : {
574 : 0 : const QString styleString( OGR_F_GetStyleString( fet.get() ) );
575 : 0 : feature.setEmbeddedSymbol( QgsOgrUtils::symbolFromStyleString( styleString, mSymbolType ).release() );
576 : 0 : }
577 : :
578 : 1101 : return true;
579 : 1101 : }
580 : :
581 : :
582 : 266 : QgsOgrFeatureSource::QgsOgrFeatureSource( const QgsOgrProvider *p )
583 : 133 : : mDataSource( p->dataSourceUri( true ) )
584 : 133 : , mAuthCfg( p->authCfg() )
585 : 133 : , mShareSameDatasetAmongLayers( p->mShareSameDatasetAmongLayers )
586 : 133 : , mLayerName( p->layerName() )
587 : 133 : , mLayerIndex( p->layerIndex() )
588 : 133 : , mSubsetString( p->mSubsetString )
589 : 133 : , mEncoding( p->textEncoding() ) // no copying - this is a borrowed pointer from Qt
590 : 133 : , mFields( p->mAttributeFields )
591 : 133 : , mFirstFieldIsFid( p->mFirstFieldIsFid )
592 : 133 : , mOgrGeometryTypeFilter( QgsOgrProvider::ogrWkbSingleFlatten( p->mOgrGeometryTypeFilter ) )
593 : 133 : , mDriverName( p->mGDALDriverName )
594 : 133 : , mCrs( p->crs() )
595 : 133 : , mWkbType( p->wkbType() )
596 : 133 : , mSharedDS( nullptr )
597 : 266 : {
598 : 133 : if ( p->mTransaction )
599 : : {
600 : 0 : mTransaction = p->mTransaction;
601 : 0 : mSharedDS = p->mTransaction->sharedDS();
602 : 0 : }
603 : 309 : for ( int i = ( p->mFirstFieldIsFid ) ? 1 : 0; i < mFields.size(); i++ )
604 : 176 : mFieldsWithoutFid.append( mFields.at( i ) );
605 : 133 : QgsOgrConnPool::instance()->ref( QgsOgrProviderUtils::connectionPoolId( mDataSource, mShareSameDatasetAmongLayers ) );
606 : 133 : }
607 : :
608 : 259 : QgsOgrFeatureSource::~QgsOgrFeatureSource()
609 : 259 : {
610 : 130 : QgsOgrConnPool::instance()->unref( QgsOgrProviderUtils::connectionPoolId( mDataSource, mShareSameDatasetAmongLayers ) );
611 : 259 : }
612 : :
613 : 91 : QgsFeatureIterator QgsOgrFeatureSource::getFeatures( const QgsFeatureRequest &request )
614 : : {
615 : 91 : return QgsFeatureIterator( new QgsOgrFeatureIterator( this, false, request, mTransaction ) );
616 : 0 : }
617 : :
618 : : ///@endcond
|