Skip to content

Commit db18d83

Browse files
committedJan 17, 2014
Oracle provider: added featureSource() support
1 parent 5315cff commit db18d83

File tree

5 files changed

+267
-115
lines changed

5 files changed

+267
-115
lines changed
 

‎src/providers/oracle/qgsoracleconn.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ struct QgsOracleLayerProperty
9696
#endif
9797
};
9898

99-
class QgsOracleConn : public QThread
99+
class QgsOracleConn : public QObject
100100
{
101101
Q_OBJECT;
102102
public:
@@ -125,7 +125,7 @@ class QgsOracleConn : public QThread
125125
/** get primary key candidates (all int4 columns) */
126126
QStringList pkCandidates( QString ownerName, QString viewName );
127127

128-
QString fieldExpression( const QgsField &fld );
128+
static QString fieldExpression( const QgsField &fld );
129129

130130
QString connInfo();
131131

‎src/providers/oracle/qgsoraclefeatureiterator.cpp

Lines changed: 83 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,45 +22,49 @@
2222

2323
#include <QObject>
2424

25-
QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleProvider *p, const QgsFeatureRequest &request )
26-
: QgsAbstractFeatureIterator( request )
27-
, P( p )
25+
QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleFeatureSource* source, bool ownSource, const QgsFeatureRequest &request )
26+
: QgsAbstractFeatureIteratorFromSource( source, ownSource, request )
2827
, mRewind( false )
2928
{
30-
P->mActiveIterators << this;
29+
mConnection = QgsOracleConn::connectDb( mSource->mUri.connectionInfo() );
30+
if ( !mConnection )
31+
{
32+
close();
33+
return;
34+
}
3135

32-
mQry = QSqlQuery( *P->mConnection );
36+
mQry = QSqlQuery( *mConnection );
3337

3438
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
3539
{
3640
mAttributeList = mRequest.subsetOfAttributes();
3741
if ( mAttributeList.isEmpty() )
38-
mAttributeList = P->attributeIndexes();
42+
mAttributeList = mSource->mFields.allAttributesList();
3943
}
4044
else
41-
mAttributeList = P->attributeIndexes();
45+
mAttributeList = mSource->mFields.allAttributesList();
4246

4347
QString whereClause;
4448

4549
switch ( request.filterType() )
4650
{
4751
case QgsFeatureRequest::FilterRect:
48-
if ( !P->mGeometryColumn.isNull() )
52+
if ( !mSource->mGeometryColumn.isNull() )
4953
{
5054
QgsRectangle rect( mRequest.filterRect() );
5155
QString bbox = QString( "mdsys.sdo_geometry(2003,%1,NULL,"
5256
"mdsys.sdo_elem_info_array(1,1003,3),"
5357
"mdsys.sdo_ordinate_array(%2,%3,%4,%5)"
5458
")" )
55-
.arg( P->mSrid < 1 ? "NULL" : QString::number( P->mSrid ) )
59+
.arg( mSource->mSrid < 1 ? "NULL" : QString::number( mSource->mSrid ) )
5660
.arg( qgsDoubleToString( rect.xMinimum() ) )
5761
.arg( qgsDoubleToString( rect.yMinimum() ) )
5862
.arg( qgsDoubleToString( rect.xMaximum() ) )
5963
.arg( qgsDoubleToString( rect.yMaximum() ) );
6064

61-
if ( !P->mSpatialIndex.isNull() )
65+
if ( !mSource->mSpatialIndex.isNull() )
6266
{
63-
whereClause = QString( "sdo_filter(%1,%2)='TRUE'" ).arg( P->quotedIdentifier( P->mGeometryColumn ) ).arg( bbox );
67+
whereClause = QString( "sdo_filter(%1,%2)='TRUE'" ).arg( QgsOracleProvider::quotedIdentifier( mSource->mGeometryColumn ) ).arg( bbox );
6468
#if 0
6569
if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect )
6670
{
@@ -74,30 +78,30 @@ QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleProvider *p, const
7478
break;
7579

7680
case QgsFeatureRequest::FilterFid:
77-
whereClause = P->whereClause( request.filterFid() );
81+
whereClause = QgsOracleUtils::whereClause( request.filterFid(), mSource->mFields, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );
7882
break;
7983

8084
case QgsFeatureRequest::FilterFids:
81-
whereClause = P->whereClause( request.filterFids() );
85+
whereClause = QgsOracleUtils::whereClause( request.filterFids(), mSource->mFields, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );
8286
break;
8387

8488
case QgsFeatureRequest::FilterNone:
8589
break;
8690
}
8791

88-
if ( P->mRequestedGeomType != QGis::WKBUnknown && P->mRequestedGeomType != P->mDetectedGeomType )
92+
if ( mSource->mRequestedGeomType != QGis::WKBUnknown && mSource->mRequestedGeomType != mSource->mDetectedGeomType )
8993
{
9094
if ( !whereClause.isEmpty() )
9195
whereClause += " AND ";
9296

93-
whereClause += QgsOracleConn::databaseTypeFilter( "featureRequest", P->mGeometryColumn, P->mRequestedGeomType );
97+
whereClause += QgsOracleConn::databaseTypeFilter( "featureRequest", mSource->mGeometryColumn, mSource->mRequestedGeomType );
9498
}
9599

96-
if ( !P->mSqlWhereClause.isEmpty() )
100+
if ( !mSource->mSqlWhereClause.isEmpty() )
97101
{
98102
if ( !whereClause.isEmpty() )
99103
whereClause += " AND ";
100-
whereClause += "(" + P->mSqlWhereClause + ")";
104+
whereClause += "(" + mSource->mSqlWhereClause + ")";
101105
}
102106

103107
if ( !openQuery( whereClause ) )
@@ -118,7 +122,7 @@ bool QgsOracleFeatureIterator::fetchFeature( QgsFeature& feature )
118122

119123
for ( ;; )
120124
{
121-
feature.initAttributes( P->fields().count() );
125+
feature.initAttributes( mSource->mFields.count() );
122126
feature.setGeometry( 0 );
123127

124128
if ( mRewind )
@@ -135,15 +139,15 @@ bool QgsOracleFeatureIterator::fetchFeature( QgsFeature& feature )
135139
int col = 0;
136140

137141
if (( mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0 ||
138-
(( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) != 0 && !P->mConnection->hasSpatial() ) )
142+
(( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) != 0 && !mConnection->hasSpatial() ) )
139143
{
140144
QByteArray *ba = static_cast<QByteArray*>( mQry.value( col++ ).data() );
141145
unsigned char *copy = new unsigned char[ba->size()];
142146
memcpy( copy, ba->constData(), ba->size() );
143147

144148
feature.setGeometryAndOwnership( copy, ba->size() );
145149

146-
if ( !P->mConnection->hasSpatial() &&
150+
if ( !mConnection->hasSpatial() &&
147151
mRequest.filterType() == QgsFeatureRequest::FilterRect &&
148152
( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) != 0 &&
149153
( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) )
@@ -162,27 +166,27 @@ bool QgsOracleFeatureIterator::fetchFeature( QgsFeature& feature )
162166

163167
QgsFeatureId fid = 0;
164168

165-
switch ( P->mPrimaryKeyType )
169+
switch ( mSource->mPrimaryKeyType )
166170
{
167-
case QgsOracleProvider::pktInt:
171+
case pktInt:
168172
// get 64bit integer from result
169173
fid = mQry.value( col++ ).toLongLong();
170-
if ( mAttributeList.contains( P->mPrimaryKeyAttrs[0] ) )
171-
feature.setAttribute( P->mPrimaryKeyAttrs[0], fid );
174+
if ( mAttributeList.contains( mSource->mPrimaryKeyAttrs[0] ) )
175+
feature.setAttribute( mSource->mPrimaryKeyAttrs[0], fid );
172176
break;
173177

174-
case QgsOracleProvider::pktRowId:
175-
case QgsOracleProvider::pktFidMap:
178+
case pktRowId:
179+
case pktFidMap:
176180
{
177181
QList<QVariant> primaryKeyVals;
178182

179-
if ( P->mPrimaryKeyType == QgsOracleProvider::pktFidMap )
183+
if ( mSource->mPrimaryKeyType == pktFidMap )
180184
{
181-
foreach ( int idx, P->mPrimaryKeyAttrs )
185+
foreach ( int idx, mSource->mPrimaryKeyAttrs )
182186
{
183-
const QgsField &fld = P->field( idx );
187+
const QgsField &fld = mSource->mFields[idx];
184188

185-
QVariant v = P->convertValue( fld.type(), mQry.value( col ).toString() );
189+
QVariant v = QgsVectorDataProvider::convertValue( fld.type(), mQry.value( col ).toString() );
186190
primaryKeyVals << v;
187191

188192
if ( mAttributeList.contains( idx ) )
@@ -196,11 +200,11 @@ bool QgsOracleFeatureIterator::fetchFeature( QgsFeature& feature )
196200
primaryKeyVals << mQry.value( col++ );
197201
}
198202

199-
fid = P->lookupFid( QVariant( primaryKeyVals ) );
203+
fid = mSource->mShared->lookupFid( QVariant( primaryKeyVals ) );
200204
}
201205
break;
202206

203-
case QgsOracleProvider::pktUnknown:
207+
case pktUnknown:
204208
Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" );
205209
return false;
206210
}
@@ -211,19 +215,19 @@ bool QgsOracleFeatureIterator::fetchFeature( QgsFeature& feature )
211215
// iterate attributes
212216
foreach ( int idx, mAttributeList )
213217
{
214-
if ( P->mPrimaryKeyAttrs.contains( idx ) )
218+
if ( mSource->mPrimaryKeyAttrs.contains( idx ) )
215219
continue;
216220

217-
const QgsField &fld = P->field( idx );
221+
const QgsField &fld = mSource->mFields[idx];
218222

219-
QVariant v = P->convertValue( fld.type(), mQry.value( col ).toString() );
223+
QVariant v = QgsVectorDataProvider::convertValue( fld.type(), mQry.value( col ).toString() );
220224
feature.setAttribute( idx, v );
221225

222226
col++;
223227
}
224228

225229
feature.setValid( true );
226-
feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups
230+
feature.setFields( &mSource->mFields ); // allow name-based attribute lookups
227231

228232
return true;
229233
}
@@ -246,14 +250,18 @@ bool QgsOracleFeatureIterator::close()
246250

247251
mQry.finish();
248252

249-
P->mActiveIterators.remove( this );
253+
if ( mConnection )
254+
mConnection->disconnect();
255+
mConnection = 0;
256+
257+
iteratorClosed();
250258

251259
return true;
252260
}
253261

254262
bool QgsOracleFeatureIterator::openQuery( QString whereClause )
255263
{
256-
if (( mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0 && P->mGeometryColumn.isNull() )
264+
if (( mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0 && mSource->mGeometryColumn.isNull() )
257265
{
258266
return false;
259267
}
@@ -264,51 +272,51 @@ bool QgsOracleFeatureIterator::openQuery( QString whereClause )
264272

265273
if (( mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0 )
266274
{
267-
query += P->quotedIdentifier( P->mGeometryColumn );
275+
query += QgsOracleProvider::quotedIdentifier( mSource->mGeometryColumn );
268276
delim = ",";
269277
}
270278

271-
switch ( P->mPrimaryKeyType )
279+
switch ( mSource->mPrimaryKeyType )
272280
{
273-
case QgsOracleProvider::pktRowId:
274-
query += delim + P->quotedIdentifier( "ROWID" );
281+
case pktRowId:
282+
query += delim + QgsOracleProvider::quotedIdentifier( "ROWID" );
275283
delim = ",";
276284
break;
277285

278-
case QgsOracleProvider::pktInt:
279-
query += delim + P->quotedIdentifier( P->field( P->mPrimaryKeyAttrs[0] ).name() );
286+
case pktInt:
287+
query += delim + QgsOracleProvider::quotedIdentifier( mSource->mFields[ mSource->mPrimaryKeyAttrs[0] ].name() );
280288
delim = ",";
281289
break;
282290

283-
case QgsOracleProvider::pktFidMap:
284-
foreach ( int idx, P->mPrimaryKeyAttrs )
291+
case pktFidMap:
292+
foreach ( int idx, mSource->mPrimaryKeyAttrs )
285293
{
286-
query += delim + P->mConnection->fieldExpression( P->field( idx ) );
294+
query += delim + mConnection->fieldExpression( mSource->mFields[idx] );
287295
delim = ",";
288296
}
289297
break;
290298

291-
case QgsOracleProvider::pktUnknown:
299+
case pktUnknown:
292300
QgsDebugMsg( "Cannot query without primary key." );
293301
return false;
294302
break;
295303
}
296304

297305
foreach ( int idx, mAttributeList )
298306
{
299-
if ( P->mPrimaryKeyAttrs.contains( idx ) )
307+
if ( mSource->mPrimaryKeyAttrs.contains( idx ) )
300308
continue;
301309

302-
query += delim + P->mConnection->fieldExpression( P->field( idx ) );
310+
query += delim + mConnection->fieldExpression( mSource->mFields[idx] );
303311
}
304312

305-
query += QString( " FROM %1 \"featureRequest\"" ).arg( P->mQuery );
313+
query += QString( " FROM %1 \"featureRequest\"" ).arg( mSource->mQuery );
306314

307315
if ( !whereClause.isEmpty() )
308316
query += QString( " WHERE %1" ).arg( whereClause );
309317

310318
QgsDebugMsg( QString( "Fetch features: %1" ).arg( query ) );
311-
if ( !P->exec( mQry, query ) )
319+
if ( !QgsOracleProvider::exec( mQry, query ) )
312320
{
313321
QgsMessageLog::logMessage( QObject::tr( "Fetching features failed.\nSQL:%1\nError: %2" )
314322
.arg( mQry.lastQuery() )
@@ -324,3 +332,26 @@ bool QgsOracleFeatureIterator::openQuery( QString whereClause )
324332

325333
return true;
326334
}
335+
336+
// -----------
337+
338+
QgsOracleFeatureSource::QgsOracleFeatureSource( const QgsOracleProvider* p )
339+
: mUri( p->mUri )
340+
, mFields( p->mAttributeFields )
341+
, mGeometryColumn( p->mGeometryColumn )
342+
, mSrid( p->mSrid )
343+
, mSpatialIndex( p->mSpatialIndex )
344+
, mDetectedGeomType( p->mDetectedGeomType )
345+
, mRequestedGeomType( p->mRequestedGeomType )
346+
, mSqlWhereClause( p->mSqlWhereClause )
347+
, mPrimaryKeyType( p->mPrimaryKeyType )
348+
, mPrimaryKeyAttrs( p->mPrimaryKeyAttrs )
349+
, mQuery( p->mQuery )
350+
, mShared( p->mShared )
351+
{
352+
}
353+
354+
QgsFeatureIterator QgsOracleFeatureSource::getFeatures( const QgsFeatureRequest& request )
355+
{
356+
return QgsFeatureIterator( new QgsOracleFeatureIterator( this, false, request ) );
357+
}

‎src/providers/oracle/qgsoraclefeatureiterator.h

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,43 @@
2222

2323
#include <QSqlQuery>
2424

25+
#include "qgsoracleprovider.h"
2526

27+
class QgsOracleConn;
2628
class QgsOracleProvider;
2729

28-
class QgsOracleFeatureIterator : public QgsAbstractFeatureIterator
30+
31+
class QgsOracleFeatureSource : public QgsAbstractFeatureSource
32+
{
33+
public:
34+
QgsOracleFeatureSource( const QgsOracleProvider* p );
35+
36+
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request );
37+
38+
protected:
39+
QgsDataSourceURI mUri;
40+
QgsFields mFields;
41+
42+
QString mGeometryColumn; //! name of the geometry column
43+
int mSrid; //! srid of column
44+
QString mSpatialIndex; //! name of spatial index of geometry column
45+
QGis::WkbType mDetectedGeomType; //! geometry type detected in the database
46+
QGis::WkbType mRequestedGeomType; //! geometry type requested in the uri
47+
QString mSqlWhereClause;
48+
QgsOraclePrimaryKeyType mPrimaryKeyType;
49+
QList<int> mPrimaryKeyAttrs;
50+
QString mQuery;
51+
52+
QSharedPointer<QgsOracleSharedData> mShared;
53+
54+
friend class QgsOracleFeatureIterator;
55+
};
56+
57+
58+
class QgsOracleFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsOracleFeatureSource>
2959
{
3060
public:
31-
QgsOracleFeatureIterator( QgsOracleProvider *p, const QgsFeatureRequest &request );
61+
QgsOracleFeatureIterator( QgsOracleFeatureSource* source, bool ownSource, const QgsFeatureRequest &request );
3262

3363
~QgsOracleFeatureIterator();
3464

@@ -42,10 +72,9 @@ class QgsOracleFeatureIterator : public QgsAbstractFeatureIterator
4272
//! fetch next feature, return true on success
4373
virtual bool fetchFeature( QgsFeature& feature );
4474

45-
QgsOracleProvider *P;
46-
4775
bool openQuery( QString whereClause );
4876

77+
QgsOracleConn *mConnection;
4978
QSqlQuery mQry;
5079
bool mRewind;
5180
QgsAttributeList mAttributeList;

‎src/providers/oracle/qgsoracleprovider.cpp

Lines changed: 92 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ QgsOracleProvider::QgsOracleProvider( QString const & uri )
4848
, mPrimaryKeyType( pktUnknown )
4949
, mDetectedGeomType( QGis::WKBUnknown )
5050
, mRequestedGeomType( QGis::WKBUnknown )
51-
, mFidCounter( 0 )
5251
, mSpatialIndex( QString::null )
52+
, mShared( new QgsOracleSharedData )
5353
{
5454
static int geomMetaType = -1;
5555
if ( geomMetaType < 0 )
@@ -197,16 +197,14 @@ QgsOracleProvider::~QgsOracleProvider()
197197
{
198198
QgsDebugMsg( "deconstructing." );
199199

200-
while ( !mActiveIterators.empty() )
201-
{
202-
QgsOracleFeatureIterator *it = *mActiveIterators.begin();
203-
QgsDebugMsg( "closing active iterator" );
204-
it->close();
205-
}
206-
207200
disconnectDb();
208201
}
209202

203+
QgsAbstractFeatureSource *QgsOracleProvider::featureSource() const
204+
{
205+
return new QgsOracleFeatureSource( this );
206+
}
207+
210208
void QgsOracleProvider::disconnectDb()
211209
{
212210
if ( mConnection )
@@ -313,20 +311,6 @@ static bool operator<( const QVariant &a, const QVariant &b )
313311
return a.canConvert( QVariant::String ) && b.canConvert( QVariant::String ) && a.toString() < b.toString();
314312
}
315313

316-
QgsFeatureId QgsOracleProvider::lookupFid( const QVariant &v )
317-
{
318-
QMap<QVariant, QgsFeatureId>::const_iterator it = mKeyToFid.find( v );
319-
320-
if ( it != mKeyToFid.constEnd() )
321-
{
322-
return it.value();
323-
}
324-
325-
mFidToKey.insert( ++mFidCounter, v );
326-
mKeyToFid.insert( v, mFidCounter );
327-
328-
return mFidCounter;
329-
}
330314

331315
QString QgsOracleProvider::pkParamWhereClause() const
332316
{
@@ -384,10 +368,10 @@ void QgsOracleProvider::appendPkParams( QgsFeatureId fid, QSqlQuery &qry ) const
384368
case pktRowId:
385369
case pktFidMap:
386370
{
387-
QMap<QgsFeatureId, QVariant>::const_iterator it = mFidToKey.find( fid );
388-
if ( it != mFidToKey.constEnd() )
371+
QVariant pkValsVariant = mShared->lookupKey( fid );
372+
if ( !pkValsVariant.isNull() )
389373
{
390-
foreach ( const QVariant &v, it.value().toList() )
374+
foreach ( const QVariant &v, pkValsVariant.toList() )
391375
{
392376
QgsDebugMsgLevel( QString( "addBindValue pk %1" ).arg( FID_TO_STRING( fid ) ), 4 );
393377
qry.addBindValue( v );
@@ -412,42 +396,43 @@ void QgsOracleProvider::appendPkParams( QgsFeatureId fid, QSqlQuery &qry ) const
412396
}
413397
}
414398

415-
QString QgsOracleProvider::whereClause( QgsFeatureId featureId ) const
399+
400+
QString QgsOracleUtils::whereClause( QgsFeatureId featureId, const QgsFields& fields, QgsOraclePrimaryKeyType primaryKeyType, const QList<int>& primaryKeyAttrs, QSharedPointer<QgsOracleSharedData> sharedData )
416401
{
417402
QString whereClause;
418403

419-
switch ( mPrimaryKeyType )
404+
switch ( primaryKeyType )
420405
{
421406
case pktInt:
422-
Q_ASSERT( mPrimaryKeyAttrs.size() == 1 );
423-
whereClause = QString( "%1=%2" ).arg( quotedIdentifier( field( mPrimaryKeyAttrs[0] ).name() ) ).arg( featureId );
407+
Q_ASSERT( primaryKeyAttrs.size() == 1 );
408+
whereClause = QString( "%1=%2" ).arg( QgsOracleConn::quotedIdentifier( fields[ primaryKeyAttrs[0] ].name() ) ).arg( featureId );
424409
break;
425410

426411
case pktRowId:
427412
case pktFidMap:
428413
{
429-
QMap<QgsFeatureId, QVariant>::const_iterator it = mFidToKey.find( featureId );
430-
if ( it != mFidToKey.constEnd() )
414+
QVariant pkValsVariant = sharedData->lookupKey( featureId );
415+
if ( !pkValsVariant.isNull() )
431416
{
432-
QList<QVariant> pkVals = it.value().toList();
417+
QList<QVariant> pkVals = pkValsVariant.toList();
433418

434-
if ( mPrimaryKeyType == pktFidMap )
419+
if ( primaryKeyType == pktFidMap )
435420
{
436-
Q_ASSERT( pkVals.size() == mPrimaryKeyAttrs.size() );
421+
Q_ASSERT( pkVals.size() == primaryKeyAttrs.size() );
437422

438423
QString delim = "";
439-
for ( int i = 0; i < mPrimaryKeyAttrs.size(); i++ )
424+
for ( int i = 0; i < primaryKeyAttrs.size(); i++ )
440425
{
441-
int idx = mPrimaryKeyAttrs[i];
442-
const QgsField &fld = field( idx );
426+
int idx = primaryKeyAttrs[i];
427+
const QgsField &fld = fields[ idx ];
443428

444-
whereClause += delim + QString( "%1=%2" ).arg( mConnection->fieldExpression( fld ) ).arg( quotedValue( pkVals[i].toString() ) );
429+
whereClause += delim + QString( "%1=%2" ).arg( QgsOracleConn::fieldExpression( fld ) ).arg( QgsOracleConn::quotedValue( pkVals[i].toString() ) );
445430
delim = " AND ";
446431
}
447432
}
448433
else
449434
{
450-
whereClause += QString( "ROWID=%1" ).arg( quotedValue( pkVals[0].toString() ) );
435+
whereClause += QString( "ROWID=%1" ).arg( QgsOracleConn::quotedValue( pkVals[0].toString() ) );
451436
}
452437
}
453438
else
@@ -467,16 +452,22 @@ QString QgsOracleProvider::whereClause( QgsFeatureId featureId ) const
467452
return whereClause;
468453
}
469454

470-
QString QgsOracleProvider::whereClause( QgsFeatureIds featureIds ) const
455+
QString QgsOracleUtils::whereClause( QgsFeatureIds featureIds, const QgsFields &fields, QgsOraclePrimaryKeyType primaryKeyType, const QList<int> &primaryKeyAttrs, QSharedPointer<QgsOracleSharedData> sharedData )
471456
{
472457
QStringList whereClauses;
473458
foreach ( const QgsFeatureId featureId, featureIds )
474459
{
475-
whereClauses << whereClause( featureId );
460+
whereClauses << whereClause( featureId, fields, primaryKeyType, primaryKeyAttrs, sharedData );
476461
}
477462
return whereClauses.join( " AND " );
478463
}
479464

465+
466+
QString QgsOracleProvider::whereClause( QgsFeatureId featureId ) const
467+
{
468+
return QgsOracleUtils::whereClause( featureId, mAttributeFields, mPrimaryKeyType, mPrimaryKeyAttrs, mShared );
469+
}
470+
480471
void QgsOracleProvider::setExtent( QgsRectangle& newExtent )
481472
{
482473
mLayerExtent.setXMaximum( newExtent.xMaximum() );
@@ -512,7 +503,7 @@ QgsFeatureIterator QgsOracleProvider::getFeatures( const QgsFeatureRequest& requ
512503
return QgsFeatureIterator();
513504
}
514505

515-
return QgsFeatureIterator( new QgsOracleFeatureIterator( this, request ) );
506+
return QgsFeatureIterator( new QgsOracleFeatureIterator( new QgsOracleFeatureSource( this ), true, request ) );
516507
}
517508

518509
/**
@@ -1330,7 +1321,7 @@ bool QgsOracleProvider::addFeatures( QgsFeatureList &flist )
13301321

13311322
if ( mPrimaryKeyType == pktRowId )
13321323
{
1333-
features->setFeatureId( lookupFid( QList<QVariant>() << QVariant( qry.lastInsertId() ) ) );
1324+
features->setFeatureId( mShared->lookupFid( QList<QVariant>() << QVariant( qry.lastInsertId() ) ) );
13341325
QgsDebugMsgLevel( QString( "new fid=%1" ).arg( features->id() ), 4 );
13351326
}
13361327
}
@@ -1362,7 +1353,7 @@ bool QgsOracleProvider::addFeatures( QgsFeatureList &flist )
13621353
primaryKeyVals << attributevec[ idx ];
13631354
}
13641355

1365-
features->setFeatureId( lookupFid( QVariant( primaryKeyVals ) ) );
1356+
features->setFeatureId( mShared->lookupFid( QVariant( primaryKeyVals ) ) );
13661357
}
13671358
QgsDebugMsgLevel( QString( "new fid=%1" ).arg( features->id() ), 4 );
13681359
}
@@ -1411,9 +1402,7 @@ bool QgsOracleProvider::deleteFeatures( const QgsFeatureIds & id )
14111402
if ( !exec( qry, sql ) )
14121403
throw OracleException( tr( "Deletion of feature %1 failed" ).arg( *it ), qry );
14131404

1414-
QVariant v = mFidToKey[ *it ];
1415-
mFidToKey.remove( *it );
1416-
mKeyToFid.remove( v );
1405+
mShared->removeFid( *it );
14171406
}
14181407

14191408
qry.finish();
@@ -1639,9 +1628,7 @@ bool QgsOracleProvider::changeAttributeValues( const QgsChangedAttributesMap & a
16391628
// update feature id map if key was changed
16401629
if ( pkChanged && mPrimaryKeyType == pktFidMap )
16411630
{
1642-
QVariant v = mFidToKey[ fid ];
1643-
mFidToKey.remove( fid );
1644-
mKeyToFid.remove( v );
1631+
QVariant v = mShared->removeFid( fid );
16451632

16461633
QList<QVariant> k = v.toList();
16471634

@@ -1654,8 +1641,7 @@ bool QgsOracleProvider::changeAttributeValues( const QgsChangedAttributesMap & a
16541641
k[i] = attrs[ idx ];
16551642
}
16561643

1657-
mFidToKey.insert( fid, k );
1658-
mKeyToFid.insert( k, fid );
1644+
mShared->insertFid( fid, k );
16591645
}
16601646
}
16611647

@@ -2954,3 +2940,57 @@ QGISEXTERN bool deleteLayer( const QString& uri, QString& errCause )
29542940
}
29552941

29562942
// vim: set sw=2 :
2943+
2944+
2945+
// ----------
2946+
2947+
2948+
QgsOracleSharedData::QgsOracleSharedData()
2949+
: mFidCounter( 0 )
2950+
{
2951+
}
2952+
2953+
QgsFeatureId QgsOracleSharedData::lookupFid( const QVariant &v )
2954+
{
2955+
QMutexLocker locker( &mMutex );
2956+
2957+
QMap<QVariant, QgsFeatureId>::const_iterator it = mKeyToFid.find( v );
2958+
2959+
if ( it != mKeyToFid.constEnd() )
2960+
{
2961+
return it.value();
2962+
}
2963+
2964+
mFidToKey.insert( ++mFidCounter, v );
2965+
mKeyToFid.insert( v, mFidCounter );
2966+
2967+
return mFidCounter;
2968+
}
2969+
2970+
QVariant QgsOracleSharedData::removeFid( QgsFeatureId fid )
2971+
{
2972+
QMutexLocker locker( &mMutex );
2973+
2974+
QVariant v = mFidToKey[ fid ];
2975+
mFidToKey.remove( fid );
2976+
mKeyToFid.remove( v );
2977+
return v;
2978+
}
2979+
2980+
void QgsOracleSharedData::insertFid( QgsFeatureId fid, const QVariant& k )
2981+
{
2982+
QMutexLocker locker( &mMutex );
2983+
2984+
mFidToKey.insert( fid, k );
2985+
mKeyToFid.insert( k, fid );
2986+
}
2987+
2988+
QVariant QgsOracleSharedData::lookupKey( QgsFeatureId featureId )
2989+
{
2990+
QMutexLocker locker( &mMutex );
2991+
2992+
QMap<QgsFeatureId, QVariant>::const_iterator it = mFidToKey.find( featureId );
2993+
if ( it != mFidToKey.constEnd() )
2994+
return it.value();
2995+
return QVariant();
2996+
}

‎src/providers/oracle/qgsoracleprovider.h

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ class QgsFeature;
3333
class QgsField;
3434
class QgsGeometry;
3535
class QgsOracleFeatureIterator;
36+
class QgsOracleSharedData;
37+
38+
enum QgsOraclePrimaryKeyType
39+
{
40+
pktUnknown,
41+
pktInt,
42+
pktRowId,
43+
pktFidMap
44+
};
3645

3746
/**
3847
\class QgsOracleProvider
@@ -71,6 +80,8 @@ class QgsOracleProvider : public QgsVectorDataProvider
7180
//! Destructor
7281
virtual ~QgsOracleProvider();
7382

83+
virtual QgsAbstractFeatureSource* featureSource() const;
84+
7485
/**
7586
* Returns the permanent storage type for this layer as a friendly name.
7687
*/
@@ -262,7 +273,6 @@ class QgsOracleProvider : public QgsVectorDataProvider
262273

263274
private:
264275
QString whereClause( QgsFeatureId featureId ) const;
265-
QString whereClause( QgsFeatureIds featureIds ) const;
266276
QString pkParamWhereClause() const;
267277
QString paramValue( QString fieldvalue, const QString &defaultValue ) const;
268278
void appendGeomParam( const QgsGeometry *geom, QSqlQuery &qry ) const;
@@ -316,7 +326,7 @@ class QgsOracleProvider : public QgsVectorDataProvider
316326
/**
317327
* Data type for the primary key
318328
*/
319-
enum { pktUnknown, pktInt, pktRowId, pktFidMap } mPrimaryKeyType;
329+
QgsOraclePrimaryKeyType mPrimaryKeyType;
320330

321331
/**
322332
* List of primary key attributes for fetching features.
@@ -382,8 +392,6 @@ class QgsOracleProvider : public QgsVectorDataProvider
382392
static QString quotedIdentifier( QString ident ) { return QgsOracleConn::quotedIdentifier( ident ); }
383393
static QString quotedValue( QVariant value ) { return QgsOracleConn::quotedValue( value ); }
384394

385-
QgsFeatureId lookupFid( const QVariant &v ); //! lookup existing mapping or add a new one
386-
387395
QMap<QVariant, QgsFeatureId> mKeyToFid; //! map key values to feature id
388396
QMap<QgsFeatureId, QVariant> mFidToKey; //! map feature back to fea
389397
QgsFeatureId mFidCounter; //! next feature id if map is used
@@ -392,8 +400,52 @@ class QgsOracleProvider : public QgsVectorDataProvider
392400
QString mSpatialIndex; //! name of spatial index of geometry column
393401
bool mHasSpatial; //! Oracle Spatial is installed
394402

403+
QSharedPointer<QgsOracleSharedData> mShared;
404+
395405
friend class QgsOracleFeatureIterator;
396-
QSet< QgsOracleFeatureIterator * > mActiveIterators;
406+
friend class QgsOracleFeatureSource;
407+
};
408+
409+
410+
/** Assorted Oracle utility functions */
411+
class QgsOracleUtils
412+
{
413+
public:
414+
static QString whereClause( QgsFeatureId featureId,
415+
const QgsFields& fields,
416+
QgsOraclePrimaryKeyType primaryKeyType,
417+
const QList<int>& primaryKeyAttrs,
418+
QSharedPointer<QgsOracleSharedData> sharedData );
419+
420+
static QString whereClause( QgsFeatureIds featureIds,
421+
const QgsFields& fields,
422+
QgsOraclePrimaryKeyType primaryKeyType,
423+
const QList<int>& primaryKeyAttrs,
424+
QSharedPointer<QgsOracleSharedData> sharedData );
397425
};
398426

427+
428+
/** Data shared between provider class and its feature sources. Ideally there should
429+
* be as few members as possible because there could be simultaneous reads/writes
430+
* from different threads and therefore locking has to be involved. */
431+
class QgsOracleSharedData
432+
{
433+
public:
434+
QgsOracleSharedData();
435+
436+
// FID lookups
437+
QgsFeatureId lookupFid( const QVariant &v ); // lookup existing mapping or add a new one
438+
QVariant removeFid( QgsFeatureId fid );
439+
void insertFid( QgsFeatureId fid, const QVariant& k );
440+
QVariant lookupKey( QgsFeatureId featureId );
441+
442+
protected:
443+
QMutex mMutex; //!< Access to all data members is guarded by the mutex
444+
445+
QgsFeatureId mFidCounter; // next feature id if map is used
446+
QMap<QVariant, QgsFeatureId> mKeyToFid; // map key values to feature id
447+
QMap<QgsFeatureId, QVariant> mFidToKey; // map feature back to fea
448+
};
449+
450+
399451
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.