Skip to content

Commit fd6dc0d

Browse files
author
Hugo Mercier
committed
Allow to open a spatialite table without primary key
1 parent 72eb1aa commit fd6dc0d

File tree

4 files changed

+31
-17
lines changed

4 files changed

+31
-17
lines changed

src/providers/spatialite/qgsspatialitefeatureiterator.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeature
3131
mHandle = QgsSpatiaLiteConnPool::instance()->acquireConnection( mSource->mSqlitePath );
3232

3333
mFetchGeometry = !mSource->mGeometryColumn.isNull() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry );
34+
mHasPrimaryKey = !mSource->mPrimaryKey.isEmpty();
35+
mRowNumber = 0;
3436

3537
QString whereClause;
3638
if ( request.filterType() == QgsFeatureRequest::FilterRect && !mSource->mGeometryColumn.isNull() )
@@ -108,6 +110,7 @@ bool QgsSpatiaLiteFeatureIterator::rewind()
108110

109111
if ( sqlite3_reset( sqliteStatement ) == SQLITE_OK )
110112
{
113+
mRowNumber = 0;
111114
return true;
112115
}
113116
else
@@ -143,7 +146,7 @@ bool QgsSpatiaLiteFeatureIterator::prepareStatement( QString whereClause )
143146
{
144147
try
145148
{
146-
QString sql = QString( "SELECT %1" ).arg( quotedPrimaryKey() );
149+
QString sql = QString( "SELECT %1" ).arg( mHasPrimaryKey ? quotedPrimaryKey() : "0" );
147150
int colIdx = 1; // column 0 is primary key
148151

149152
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
@@ -320,10 +323,19 @@ bool QgsSpatiaLiteFeatureIterator::getFeature( sqlite3_stmt *stmt, QgsFeature &f
320323
{
321324
if ( ic == 0 )
322325
{
323-
// first column always contains the ROWID (or the primary key)
324-
QgsFeatureId fid = sqlite3_column_int64( stmt, ic );
325-
QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 3 );
326-
feature.setFeatureId( fid );
326+
if ( mHasPrimaryKey )
327+
{
328+
// first column always contains the ROWID (or the primary key)
329+
QgsFeatureId fid = sqlite3_column_int64( stmt, ic );
330+
QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 3 );
331+
feature.setFeatureId( fid );
332+
}
333+
else
334+
{
335+
// autoincrement a row number
336+
mRowNumber++;
337+
feature.setFeatureId( mRowNumber );
338+
}
327339
}
328340
else if ( mFetchGeometry && ic == mGeomColIdx )
329341
{

src/providers/spatialite/qgsspatialitefeatureiterator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ class QgsSpatiaLiteFeatureIterator : public QgsAbstractFeatureIteratorFromSource
9393

9494
//! Set to true, if geometry is in the requested columns
9595
bool mFetchGeometry;
96+
97+
bool mHasPrimaryKey;
98+
QgsFeatureId mRowNumber;
9699
};
97100

98101
#endif // QGSSPATIALITEFEATUREITERATOR_H

src/providers/spatialite/qgsspatialiteprovider.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri )
497497
closeDb();
498498
return;
499499
}
500-
enabledCapabilities = QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::SelectGeometryAtId;
500+
enabledCapabilities = mPrimaryKey.isEmpty() ? 0 : (QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::SelectGeometryAtId);
501501
if (( mTableBased || mViewBased ) && !mReadOnly )
502502
{
503503
// enabling editing only for Tables [excluding Views and VirtualShapes]

tests/src/python/test_qgsspatialiteprovider.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ def setUpClass(cls):
7676
sql = "SELECT AddGeometryColumn('test_q', 'geometry', 4326, 'POLYGON', 'XY')"
7777
cur.execute(sql)
7878
sql = "INSERT INTO test_q (id, name, geometry) "
79-
sql += "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
79+
sql += "VALUES (11, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
8080
cur.execute(sql)
8181
sql = "INSERT INTO test_q (id, name, geometry) "
82-
sql += "VALUES (2, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
82+
sql += "VALUES (21, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
8383
cur.execute(sql)
8484

8585
# simple table with a geometry column named 'Geometry'
@@ -150,32 +150,31 @@ def test_queries(self):
150150
"""Test loading of query-based layers"""
151151

152152
# a query with a geometry, but no unique id
153-
# this allows to load a query without unique id
154-
# however, functions relying on such a unique id would fail
153+
# the id will be autoincremented
155154
l = QgsVectorLayer("dbname=%s table='(select * from test_q)' (geometry)" % self.dbname, "test_pg_query1", "spatialite")
156155
assert(l.isValid())
157-
# the id() is not consistent
156+
# the id() is autoincremented
158157
sum_id1 = sum(f.id() for f in l.getFeatures())
159158
# the attribute 'id' works
160159
sum_id2 = sum(f.attributes()[0] for f in l.getFeatures())
161-
assert(sum_id1 == 0)
162-
assert(sum_id2 == 3)
160+
assert(sum_id1 == 3) # 1+2
161+
assert(sum_id2 == 32) # 11 + 21
163162

164163
# and now with an id declared
165164
l = QgsVectorLayer("dbname=%s table='(select * from test_q)' (geometry) key='id'" % self.dbname, "test_pg_query1", "spatialite")
166165
assert(l.isValid())
167166
sum_id1 = sum(f.id() for f in l.getFeatures())
168167
sum_id2 = sum(f.attributes()[0] for f in l.getFeatures())
169-
assert(sum_id1 == 3)
170-
assert(sum_id2 == 3)
168+
assert(sum_id1 == 32)
169+
assert(sum_id2 == 32)
171170

172171
# a query, but no geometry
173172
l = QgsVectorLayer("dbname=%s table='(select id,name from test_q)' key='id'" % self.dbname, "test_pg_query1", "spatialite")
174173
assert(l.isValid())
175174
sum_id1 = sum(f.id() for f in l.getFeatures())
176175
sum_id2 = sum(f.attributes()[0] for f in l.getFeatures())
177-
assert(sum_id1 == 3)
178-
assert(sum_id2 == 3)
176+
assert(sum_id1 == 32)
177+
assert(sum_id2 == 32)
179178

180179
def test_case(self):
181180
"""Test case sensitivity issues"""

0 commit comments

Comments
 (0)