Skip to content

Commit 854f237

Browse files
committedJan 31, 2013
Merge pull request #416 from szekerest/master
Update MS SQL driver to new vector API
2 parents a396613 + 3b29fad commit 854f237

File tree

6 files changed

+554
-407
lines changed

6 files changed

+554
-407
lines changed
 

‎src/providers/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ADD_SUBDIRECTORY(delimitedtext)
99
ADD_SUBDIRECTORY(osm)
1010
ADD_SUBDIRECTORY(sqlanywhere)
1111
ADD_SUBDIRECTORY(gdal)
12-
#ADD_SUBDIRECTORY(mssql) # TODO: enable when migrated to new api
12+
ADD_SUBDIRECTORY(mssql)
1313
ADD_SUBDIRECTORY(ows)
1414
ADD_SUBDIRECTORY(wcs)
1515
ADD_SUBDIRECTORY(gpx)

‎src/providers/mssql/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
2+
SET (MSSQL_SRCS qgsmssqlprovider.cpp qgsmssqlgeometryparser.cpp qgsmssqlsourceselect.cpp qgsmssqltablemodel.cpp qgsmssqlnewconnection.cpp qgsmssqldataitems.cpp qgsmssqlfeatureiterator.cpp)
13

2-
SET (MSSQL_SRCS qgsmssqlprovider.cpp qgsmssqlgeometryparser.cpp qgsmssqlsourceselect.cpp qgsmssqltablemodel.cpp qgsmssqlnewconnection.cpp qgsmssqldataitems.cpp)
3-
4-
SET (MSSQL_MOC_HDRS qgsmssqlprovider.h qgsmssqlsourceselect.h qgsmssqltablemodel.h qgsmssqlnewconnection.h qgsmssqldataitems.h)
4+
SET (MSSQL_MOC_HDRS qgsmssqlprovider.h qgsmssqlsourceselect.h qgsmssqltablemodel.h qgsmssqlnewconnection.h qgsmssqldataitems.h qgsmssqlfeatureiterator.h)
55

66
########################################################
77
# Build
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
/***************************************************************************
2+
qgsmssqlfeatureiterator.cpp - description
3+
-------------------
4+
begin : 2011-10-08
5+
copyright : (C) 2011 by Tamas Szekeres
6+
email : szekerest at gmail.com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsmssqlfeatureiterator.h"
19+
#include "qgsmssqlprovider.h"
20+
#include "qgslogger.h"
21+
22+
#include <QObject>
23+
#include <QTextStream>
24+
25+
26+
QgsMssqlFeatureIterator::QgsMssqlFeatureIterator( QgsMssqlProvider* provider, const QgsFeatureRequest& request)
27+
: QgsAbstractFeatureIterator( request ), mProvider( provider )
28+
{
29+
mIsOpen = false;
30+
BuildStatement( request );
31+
32+
mQuery = NULL;
33+
34+
if ( mProvider->mQuery.isActive() )
35+
{
36+
mUseProviderQuery = false;
37+
// create a separate database connection if the default query is active
38+
QgsDebugMsg( "Creating a separate database connection" );
39+
QString id;
40+
// QString::sprintf adds 0x prefix
41+
id.sprintf("%08p", this);
42+
mDatabase = mProvider->mDatabase.cloneDatabase(mProvider->mDatabase, id);
43+
if (!mDatabase.open())
44+
{
45+
QgsDebugMsg( "Failed to open database" );
46+
QString msg = mDatabase.lastError().text();
47+
QgsDebugMsg( msg );
48+
return;
49+
}
50+
// create sql query
51+
mQuery = new QSqlQuery( mDatabase );
52+
}
53+
else
54+
{
55+
mUseProviderQuery = true;
56+
mQuery = &mProvider->mQuery;
57+
}
58+
// start selection
59+
rewind();
60+
}
61+
62+
63+
QgsMssqlFeatureIterator::~QgsMssqlFeatureIterator()
64+
{
65+
if (!mUseProviderQuery)
66+
{
67+
if (mQuery)
68+
delete mQuery;
69+
mDatabase.close();
70+
}
71+
else if (mIsOpen)
72+
close();
73+
}
74+
75+
void QgsMssqlFeatureIterator::BuildStatement( const QgsFeatureRequest& request )
76+
{
77+
// build sql statement
78+
mStatement = QString( "select " );
79+
int fieldCount = 0;
80+
mFidCol = -1;
81+
mGeometryCol = -1;
82+
83+
if (!request.subsetOfAttributes().empty())
84+
{
85+
// subset of attributes has been specified
86+
for ( QgsAttributeList::const_iterator it = request.subsetOfAttributes().begin(); it != request.subsetOfAttributes().end(); ++it )
87+
{
88+
if ( fieldCount != 0 )
89+
mStatement += ",";
90+
mStatement += "[" + mProvider->mAttributeFields[*it].name() + "]";
91+
92+
if ( !mProvider->mFidColName.isEmpty() && mProvider->mFidColName == mProvider->mAttributeFields[*it].name() )
93+
mFidCol = fieldCount;
94+
95+
++fieldCount;
96+
mAttributesToFetch.append(*it);
97+
}
98+
}
99+
else
100+
{
101+
// get all attributes
102+
for (int i = 0; i < mProvider->mAttributeFields.count(); i++)
103+
{
104+
if ( fieldCount != 0 )
105+
mStatement += ",";
106+
mStatement += "[" + mProvider->mAttributeFields[i].name() + "]";
107+
108+
if ( !mProvider->mFidColName.isEmpty() && mProvider->mFidColName == mProvider->mAttributeFields[i].name() )
109+
mFidCol = fieldCount;
110+
111+
++fieldCount;
112+
mAttributesToFetch.append(i);
113+
}
114+
}
115+
// get fid col if not yet required
116+
if ( mFidCol == -1 && !mProvider->mFidColName.isEmpty() )
117+
{
118+
if ( fieldCount != 0 )
119+
mStatement += ",";
120+
mStatement += "[" + mProvider->mFidColName + "]";
121+
mFidCol = fieldCount;
122+
++fieldCount;
123+
}
124+
// get geometry col
125+
if ( request.flags() != QgsFeatureRequest::NoGeometry && !mProvider->mGeometryColName.isEmpty() )
126+
{
127+
if ( fieldCount != 0 )
128+
mStatement += ",";
129+
mStatement += "[" + mProvider->mGeometryColName + "]";
130+
mGeometryCol = fieldCount;
131+
++fieldCount;
132+
}
133+
134+
mStatement += " from ";
135+
if ( !mProvider->mSchemaName.isEmpty() )
136+
mStatement += "[" + mProvider->mSchemaName + "].";
137+
138+
mStatement += "[" + mProvider->mTableName + "]";
139+
140+
bool filterAdded = false;
141+
// set spatial filter
142+
if ( request.filterType() & QgsFeatureRequest::FilterRect)
143+
{
144+
// polygons should be CCW for SqlGeography
145+
QString r;
146+
QTextStream foo( &r );
147+
148+
foo.setRealNumberPrecision( 8 );
149+
foo.setRealNumberNotation( QTextStream::FixedNotation );
150+
foo << request.filterRect().xMinimum() << " " << request.filterRect().yMinimum() << ", "
151+
<< request.filterRect().xMaximum() << " " << request.filterRect().yMinimum() << ", "
152+
<< request.filterRect().xMaximum() << " " << request.filterRect().yMaximum() << ", "
153+
<< request.filterRect().xMinimum() << " " << request.filterRect().yMaximum() << ", "
154+
<< request.filterRect().xMinimum() << " " << request.filterRect().yMinimum();
155+
156+
mStatement += QString( " where [%1].STIntersects([%2]::STGeomFromText('POLYGON((%3))',%4)) = 1" ).arg(
157+
mProvider->mGeometryColName, mProvider->mGeometryColType, r, QString::number( mProvider->mSRId ) );
158+
filterAdded = true;
159+
}
160+
161+
// set fid filter
162+
if ( (request.filterType() & QgsFeatureRequest::FilterFid) && !mProvider->mFidColName.isEmpty() )
163+
{
164+
// set attribute filter
165+
if ( !filterAdded )
166+
mStatement += QString( " where [%1] = %2" ).arg( mProvider->mFidColName, QString::number( request.filterFid() ) );
167+
else
168+
mStatement +=QString( " and [%1] = %2" ).arg( mProvider->mFidColName, QString::number( request.filterFid() ) );
169+
filterAdded = true;
170+
}
171+
172+
if ( !mProvider->mSqlWhereClause.isEmpty() )
173+
{
174+
if ( !filterAdded )
175+
mStatement += " where (" + mProvider->mSqlWhereClause + ")";
176+
else
177+
mStatement += " and (" + mProvider->mSqlWhereClause + ")";
178+
filterAdded = true;
179+
}
180+
181+
if ( fieldCount == 0 )
182+
{
183+
QgsDebugMsg( "QgsMssqlProvider::select no fields have been requested" );
184+
mStatement.clear();
185+
}
186+
}
187+
188+
189+
bool QgsMssqlFeatureIterator::nextFeature( QgsFeature& feature )
190+
{
191+
feature.setValid( false );
192+
193+
if (!mQuery)
194+
return false;
195+
196+
if ( !mQuery->isActive() )
197+
{
198+
QgsDebugMsg( "Read attempt on inactive query" );
199+
return false;
200+
}
201+
202+
if ( mQuery->next() )
203+
{
204+
feature.initAttributes( mProvider->mAttributeFields.count() );
205+
feature.setFields( &mProvider->mAttributeFields ); // allow name-based attribute lookups
206+
207+
for (int i = 0; i < mAttributesToFetch.count(); i++)
208+
{
209+
QVariant v = mQuery->value( i );
210+
feature.setAttribute( mAttributesToFetch[i], mQuery->value( i ) );
211+
}
212+
213+
if ( mFidCol >= 0 )
214+
{
215+
feature.setFeatureId( mQuery->value( mFidCol ).toLongLong() );
216+
}
217+
218+
if ( mGeometryCol >= 0 )
219+
{
220+
QByteArray ar = mQuery->value( mGeometryCol ).toByteArray();
221+
unsigned char* wkb = mProvider->parser.ParseSqlGeometry(( unsigned char* )ar.data(), ar.size() );
222+
if ( wkb )
223+
{
224+
feature.setGeometryAndOwnership( wkb, mProvider->parser.GetWkbLen() );
225+
}
226+
}
227+
228+
feature.setValid( true );
229+
return true;
230+
}
231+
return false;
232+
}
233+
234+
235+
bool QgsMssqlFeatureIterator::rewind()
236+
{
237+
if ( mStatement.isEmpty() )
238+
{
239+
QgsDebugMsg( "QgsMssqlFeatureIterator::rewind on empty statement" );
240+
return false;
241+
}
242+
243+
if (!mQuery)
244+
return false;
245+
246+
mQuery->clear();
247+
mQuery->setForwardOnly( true );
248+
if ( !mQuery->exec( mStatement ) )
249+
{
250+
QString msg = mQuery->lastError().text();
251+
QgsDebugMsg( msg );
252+
}
253+
else
254+
mIsOpen = true;
255+
256+
return true;
257+
}
258+
259+
bool QgsMssqlFeatureIterator::close()
260+
{
261+
mIsOpen = false;
262+
if (!mQuery)
263+
return false;
264+
265+
if ( !mQuery->isActive() )
266+
{
267+
QgsDebugMsg( "QgsMssqlFeatureIterator::close on inactive query" );
268+
return false;
269+
}
270+
271+
mQuery->finish();
272+
return true;
273+
}
274+
275+
///////////////
276+
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/***************************************************************************
2+
qgsmssqlfeatureiterator.h - description
3+
-------------------
4+
begin : 2011-10-08
5+
copyright : (C) 2011 by Tamas Szekeres
6+
email : szekerest at gmail.com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#ifndef QGSMSSQLFEATUREITERATOR_H
19+
#define QGSMSSQLFEATUREITERATOR_H
20+
21+
#include "qgsmssqlprovider.h"
22+
#include "qgsfeatureiterator.h"
23+
#include <QtSql/QSqlDatabase>
24+
#include <QtSql/QSqlQuery>
25+
#include <QtSql/QSqlError>
26+
27+
class QgsMssqlProvider;
28+
29+
class QgsMssqlFeatureIterator : public QgsAbstractFeatureIterator
30+
{
31+
public:
32+
QgsMssqlFeatureIterator( QgsMssqlProvider* provider, const QgsFeatureRequest& request);
33+
34+
~QgsMssqlFeatureIterator();
35+
36+
//! fetch next feature, return true on success
37+
virtual bool nextFeature( QgsFeature& feature );
38+
39+
//! reset the iterator to the starting position
40+
virtual bool rewind();
41+
42+
//! end of iterating: free the resources / lock
43+
virtual bool close();
44+
45+
protected:
46+
QgsMssqlProvider* mProvider;
47+
48+
void BuildStatement( const QgsFeatureRequest& request );
49+
50+
private:
51+
// The current database
52+
QSqlDatabase mDatabase;
53+
54+
// The current sql query
55+
QSqlQuery* mQuery;
56+
57+
// Use query on provider (no new connection added)
58+
bool mUseProviderQuery;
59+
60+
// The current sql statement
61+
QString mStatement;
62+
63+
// Open connection flag
64+
bool mIsOpen;
65+
66+
// Field index of FID column
67+
long mFidCol;
68+
69+
// Field index of geometry column
70+
long mGeometryCol;
71+
72+
// List of attribute indices to fetch with nextFeature calls
73+
QgsAttributeList mAttributesToFetch;
74+
};
75+
76+
#endif // QGSMSSQLFEATUREITERATOR_H

‎src/providers/mssql/qgsmssqlprovider.cpp

Lines changed: 185 additions & 362 deletions
Large diffs are not rendered by default.

‎src/providers/mssql/qgsmssqlprovider.h

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* *
1616
***************************************************************************/
1717

18+
#ifndef QGSMSSQLPROVIDER_H
19+
#define QGSMSSQLPROVIDER_H
1820

1921
#include "qgsvectordataprovider.h"
2022
#include "qgscoordinatereferencesystem.h"
@@ -31,6 +33,8 @@ class QgsField;
3133
class QFile;
3234
class QTextStream;
3335

36+
class QgsMssqlFeatureIterator;
37+
3438
#include "qgsdatasourceuri.h"
3539
#include "qgsgeometry.h"
3640

@@ -121,18 +125,6 @@ class QgsMssqlProvider : public QgsVectorDataProvider
121125
*/
122126
virtual QStringList subLayers() const;
123127

124-
/** Select features based on a bounding rectangle. Features can be retrieved with calls to nextFeature.
125-
* @param fetchAttributes list of attributes which should be fetched
126-
* @param rect spatial filter
127-
* @param fetchGeometry true if the feature geometry should be fetched
128-
* @param useIntersect true if an accurate intersection test should be used,
129-
* false if a test based on bounding box is sufficient
130-
*/
131-
virtual void select( QgsAttributeList fetchAttributes = QgsAttributeList(),
132-
QgsRectangle rect = QgsRectangle(),
133-
bool fetchGeometry = true,
134-
bool useIntersect = false );
135-
136128
/**
137129
* Returns the minimum value of an attribute
138130
* @param index the index of the attribute
@@ -164,27 +156,10 @@ class QgsMssqlProvider : public QgsVectorDataProvider
164156
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 );
165157

166158
/**
167-
* Get the next feature resulting from a select operation.
168-
* @param feature feature which will receive data from the provider
169-
* @return true when there was a feature to fetch, false when end was hit
170-
*
171-
* mFile should be open with the file pointer at the record of the next
172-
* feature, or EOF. The feature found on the current line is parsed.
159+
* Get feature iterator.
160+
* @return QgsFeatureIterator to iterate features
173161
*/
174-
virtual bool nextFeature( QgsFeature& feature );
175-
176-
/**
177-
* Gets the feature at the given feature ID.
178-
* @param featureId id of the feature
179-
* @param feature feature which will receive the data
180-
* @param fetchGeoemtry if true, geometry will be fetched from the provider
181-
* @param fetchAttributes a list containing the indexes of the attribute fields to copy
182-
* @return True when feature was found, otherwise false
183-
*/
184-
virtual bool featureAtId( QgsFeatureId featureId,
185-
QgsFeature& feature,
186-
bool fetchGeometry = true,
187-
QgsAttributeList fetchAttributes = QgsAttributeList() );
162+
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request );
188163

189164
/**
190165
* Get feature type.
@@ -205,10 +180,7 @@ class QgsMssqlProvider : public QgsVectorDataProvider
205180
* Return a map of indexes with field names for this layer
206181
* @return map of fields
207182
*/
208-
virtual const QgsFieldMap & fields() const;
209-
210-
/** Restart reading features from previous select operation */
211-
virtual void rewind();
183+
virtual const QgsFields & fields() const;
212184

213185
/** Accessor for sql where clause used to limit dataset */
214186
QString subsetString();
@@ -329,13 +301,11 @@ class QgsMssqlProvider : public QgsVectorDataProvider
329301
private:
330302

331303
//! Fields
332-
QgsFieldMap mAttributeFields;
304+
QgsFields mAttributeFields;
333305
QMap<int, QVariant> mDefaultValues;
334306

335307
QgsMssqlGeometryParser parser;
336308

337-
int mFieldCount; // Note: this includes field count for wkt field
338-
339309
//! Layer extent
340310
QgsRectangle mExtent;
341311

@@ -348,10 +318,8 @@ class QgsMssqlProvider : public QgsVectorDataProvider
348318
int mGeomType;
349319

350320
long mNumberFeatures;
351-
long mFidCol;
352321
QString mFidColName;
353322
long mSRId;
354-
long mGeometryCol;
355323
QString mGeometryColName;
356324
QString mGeometryColType;
357325

@@ -389,4 +357,8 @@ class QgsMssqlProvider : public QgsVectorDataProvider
389357

390358
static void mssqlWkbTypeAndDimension( QGis::WkbType wkbType, QString &geometryType, int &dim );
391359
static QGis::WkbType getWkbType( QString geometryType, int dim );
360+
361+
friend class QgsMssqlFeatureIterator;
392362
};
363+
364+
#endif // QGSMSSQLPROVIDER_H

0 commit comments

Comments
 (0)
Please sign in to comment.