1
/***************************************************************************
2
qgsspatialiteprovider.cpp Data provider for SpatiaLite DBMS
4
copyright : (C) 2008 Sandro Furieri
5
email : a.furieri@lqt.it
6
***************************************************************************/
8
/***************************************************************************
10
* This program is free software; you can redistribute it and/or modify *
11
* it under the terms of the GNU General Public License as published by *
12
* the Free Software Foundation; either version 2 of the License, or *
13
* (at your option) any later version. *
15
***************************************************************************/
20
#include <qgsapplication.h>
21
#include <qgsfeature.h>
23
#include <qgsgeometry.h>
24
#include <qgsmessageoutput.h>
25
#include <qgsrectangle.h>
26
#include <qgscoordinatereferencesystem.h>
28
#include "qgsprovidercountcalcevent.h"
29
#include "qgsproviderextentcalcevent.h"
31
#include "qgsspatialiteprovider.h"
33
#include "qgslogger.h"
36
#define strcasecmp(a,b) stricmp(a,b)
39
const QString SPATIALITE_KEY = "spatialite";
40
const QString SPATIALITE_DESCRIPTION = "SpatiaLite data provider";
42
QMap < QString, QgsSpatiaLiteProvider::SqliteHandles * >QgsSpatiaLiteProvider::SqliteHandles::handles;
44
QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri ): QgsVectorDataProvider( uri ),
45
geomType( QGis::WKBUnknown ), sqliteHandle( NULL ), sqliteStatement( NULL ), mSrid( -1 ), spatialIndexRTree( false ), spatialIndexMbrCache( false )
47
QgsDataSourceURI anUri = QgsDataSourceURI( uri );
49
// parsing members from the uri structure
50
mTableName = anUri.table();
51
mGeometryColumn = anUri.geometryColumn();
52
mSqlitePath = anUri.database();
53
mSubsetString = anUri.sql();
55
// trying to open the SQLite DB
58
handle = SqliteHandles::openDb( mSqlitePath );
64
sqliteHandle = handle->handle();
66
if ( !checkLayerType() ) // check if this one Layer is based on a Table, View or VirtualShapefile
72
QgsLogger::critical( "Invalid SpatiaLite layer" );
76
enabledCapabilities = QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::SelectGeometryAtId;
77
if ( mTableBased && !mReadOnly )
79
// enabling editing only for Tables [excluding Views and VirtualShapes]
80
enabledCapabilities |= QgsVectorDataProvider::DeleteFeatures;
81
enabledCapabilities |= QgsVectorDataProvider::ChangeGeometries;
82
enabledCapabilities |= QgsVectorDataProvider::ChangeAttributeValues;
83
enabledCapabilities |= QgsVectorDataProvider::AddFeatures;
84
enabledCapabilities |= QgsVectorDataProvider::AddAttributes;
87
if ( !getGeometryDetails() ) // gets srid and geometry type
89
// the table is not a geometry table
93
QgsLogger::critical( "Invalid SpatiaLite layer" );
97
if ( !getTableSummary() ) // gets the extent and feature count
102
QgsLogger::critical( "Invalid SpatiaLite layer" );
106
// load the columns list
108
if ( sqliteHandle == NULL )
112
QgsLogger::critical( "Invalid SpatiaLite layer" );
115
//fill type names into sets
117
<< QgsVectorDataProvider::NativeType( tr( "Binary object (BLOB)" ), "SQLITE_BLOB", QVariant::ByteArray )
118
<< QgsVectorDataProvider::NativeType( tr( "Text" ), "SQLITE_TEXT", QVariant::String )
119
<< QgsVectorDataProvider::NativeType( tr( "Decimal number (double)" ), "SQLITE_FLOAT", QVariant::Double, 0, 20, 0, 20 )
120
<< QgsVectorDataProvider::NativeType( tr( "Whole number (integer)" ), "SQLITE_INTEGER", QVariant::LongLong, 0, 20 )
124
QgsSpatiaLiteProvider::~QgsSpatiaLiteProvider()
129
void QgsSpatiaLiteProvider::loadFields()
141
attributeFields.clear();
144
QString sql = QString( "PRAGMA table_info(\"%1\")" ).arg( mTableName );
146
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
147
if ( ret != SQLITE_OK )
153
for ( i = 1; i <= rows; i++ )
155
QString name = QString::fromUtf8( results[( i * columns ) + 1] );
156
const char *type = results[( i * columns ) + 2];
157
QString pk = results[( i * columns ) + 5];
158
if ( pk.toInt() != 0 )
160
// found a Primary Key column
165
if ( name != mGeometryColumn )
167
// for sure any SQLite value can be represented as SQLITE_TEXT
168
QVariant::Type fieldType = QVariant::String;
170
// making some assumptions in order to guess a more realistic type
171
if ( strcasecmp( type, "int" ) == 0 ||
172
strcasecmp( type, "integer" ) == 0 ||
173
strcasecmp( type, "bigint" ) == 0 ||
174
strcasecmp( type, "smallint" ) == 0 || strcasecmp( type, "tinyint" ) == 0 || strcasecmp( type, "boolean" ) == 0 )
176
fieldType = QVariant::Int;
178
else if ( strcasecmp( type, "real" ) == 0 ||
179
strcasecmp( type, "double" ) == 0 ||
180
strcasecmp( type, "double precision" ) == 0 || strcasecmp( type, "float" ) == 0 )
182
fieldType = QVariant::Double;
185
attributeFields.insert( fldNo++, QgsField( name, fieldType, type, 0, 0, "" ) );
189
sqlite3_free_table( results );
193
// setting the Primary Key column name
194
mPrimaryKey = pkName;
201
if ( errMsg != NULL )
203
QString error = "loadFields() SQL error: ";
205
QgsLogger::critical( error );
206
sqlite3_free( errMsg );
211
QString QgsSpatiaLiteProvider::storageType() const
213
return "SQLite database with SpatiaLite extension";
217
bool QgsSpatiaLiteProvider::featureAtId( int featureId, QgsFeature & feature, bool fetchGeometry, QgsAttributeList fetchAttributes )
219
sqlite3_stmt *stmt = NULL;
221
QString sql = "SELECT ROWID";
222
for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it )
224
const QgsField & fld = field( *it );
225
const QString & fieldname = fld.name();
232
sql += QString( ", AsBinary(\"%1\")" ).arg( mGeometryColumn );
234
sql += QString( " FROM \"%1\" WHERE ROWID = %2" ).arg( mTableName ).arg( featureId );
236
if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
238
// some error occurred
239
QString errCause = sqlite3_errmsg( sqliteHandle );
240
QString msg = tr( "SQLite error: %1\n\nSQL: %2" ).arg( sql ).arg( errCause );
241
QgsLogger::critical( msg );
245
int ret = sqlite3_step( stmt );
246
if ( ret == SQLITE_DONE )
248
// there are no more rows to fetch - we can stop looping destroying the SQLite statement
249
sqlite3_finalize( stmt );
252
if ( ret == SQLITE_ROW )
254
// one valid row has been fetched from the result set
257
// no geometry was required
258
feature.setGeometryAndOwnership( 0, 0 );
262
int n_columns = sqlite3_column_count( stmt );
263
for ( ic = 0; ic < n_columns; ic++ )
267
// first column always contains the ROWID
268
feature.setFeatureId( sqlite3_column_int( stmt, ic ) );
272
// iterate attributes
273
bool fetched = false;
275
for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); it++ )
279
// ok, this one is the corresponding attribure
280
if ( sqlite3_column_type( stmt, ic ) == SQLITE_INTEGER )
283
feature.addAttribute( *it, sqlite3_column_int( stmt, ic ) );
286
else if ( sqlite3_column_type( stmt, ic ) == SQLITE_FLOAT )
289
feature.addAttribute( *it, sqlite3_column_double( stmt, ic ) );
292
else if ( sqlite3_column_type( stmt, ic ) == SQLITE_TEXT )
295
const char *txt = ( const char * ) sqlite3_column_text( stmt, ic );
296
QString str = QString::fromUtf8( txt );
297
feature.addAttribute( *it, str );
303
feature.addAttribute( *it, QVariant( QString::null ) );
315
QString geoCol = QString( "AsBinary(\"%1\")" ).arg( mGeometryColumn );
316
if ( strcasecmp( geoCol.toUtf8().constData(), sqlite3_column_name( stmt, ic ) ) == 0 )
318
if ( sqlite3_column_type( stmt, ic ) == SQLITE_BLOB )
320
const void *blob = sqlite3_column_blob( stmt, ic );
321
size_t blob_size = sqlite3_column_bytes( stmt, ic );
322
unsigned char *featureGeom = new unsigned char[blob_size + 1];
323
memset( featureGeom, '\0', blob_size + 1 );
324
memcpy( featureGeom, blob, blob_size );
325
feature.setGeometryAndOwnership( featureGeom, blob_size + 1 );
330
feature.setGeometryAndOwnership( 0, 0 );
339
// some unexpected error occurred
340
QString error = "sqlite3_step() error: ";
341
error += sqlite3_errmsg( sqliteHandle );
342
QgsLogger::critical( error );
343
sqlite3_finalize( stmt );
346
sqlite3_finalize( stmt );
351
bool QgsSpatiaLiteProvider::nextFeature( QgsFeature & feature )
353
feature.setValid( false );
356
QgsLogger::critical( "Read attempt on an invalid SpatiaLite data source" );
360
if ( sqliteStatement == NULL )
362
QgsLogger::critical( "Invalid current SQLite statement" );
366
int ret = sqlite3_step( sqliteStatement );
367
if ( ret == SQLITE_DONE )
369
// there are no more rows to fetch - we can stop looping destroying the SQLite statement
370
sqlite3_finalize( sqliteStatement );
371
sqliteStatement = NULL;
374
if ( ret == SQLITE_ROW )
376
// one valid row has been fetched from the result set
379
// no geometry was required
380
feature.setGeometryAndOwnership( 0, 0 );
384
int n_columns = sqlite3_column_count( sqliteStatement );
385
for ( ic = 0; ic < n_columns; ic++ )
389
// first column always contains the ROWID
390
feature.setFeatureId( sqlite3_column_int( sqliteStatement, ic ) );
394
// iterate attributes
395
bool fetched = false;
397
for ( QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin(); it != mAttributesToFetch.constEnd(); it++ )
401
// ok, this one is the corresponding attribure
402
if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_INTEGER )
405
feature.addAttribute( *it, sqlite3_column_int( sqliteStatement, ic ) );
408
else if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_FLOAT )
411
feature.addAttribute( *it, sqlite3_column_double( sqliteStatement, ic ) );
414
else if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_TEXT )
417
const char *txt = ( const char * ) sqlite3_column_text( sqliteStatement, ic );
418
QString str = QString::fromUtf8( txt );
419
feature.addAttribute( *it, str );
425
feature.addAttribute( *it, QVariant( QString::null ) );
437
QString geoCol = QString( "AsBinary(\"%1\")" ).arg( mGeometryColumn );
438
if ( strcasecmp( geoCol.toUtf8().constData(), sqlite3_column_name( sqliteStatement, ic ) ) == 0 )
440
if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_BLOB )
442
const void *blob = sqlite3_column_blob( sqliteStatement, ic );
443
size_t blob_size = sqlite3_column_bytes( sqliteStatement, ic );
444
unsigned char *featureGeom = new unsigned char[blob_size + 1];
445
memset( featureGeom, '\0', blob_size + 1 );
446
memcpy( featureGeom, blob, blob_size );
447
feature.setGeometryAndOwnership( featureGeom, blob_size + 1 );
452
feature.setGeometryAndOwnership( 0, 0 );
461
// some unexpected error occurred
462
QString error = "sqlite3_step() error: ";
463
error += sqlite3_errmsg( sqliteHandle );
464
QgsLogger::critical( error );
465
sqlite3_finalize( sqliteStatement );
466
sqliteStatement = NULL;
470
feature.setValid( true );
474
QString QgsSpatiaLiteProvider::subsetString()
476
return mSubsetString;
479
bool QgsSpatiaLiteProvider::setSubsetString( QString theSQL )
481
QString prevSubsetString = mSubsetString;
482
mSubsetString = theSQL;
485
QgsDataSourceURI uri = QgsDataSourceURI( dataSourceUri() );
486
uri.setSql( mSubsetString );
487
setDataSourceUri( uri.uri() );
489
// update feature count and extents
490
if ( getTableSummary() )
493
mSubsetString = prevSubsetString;
496
uri = QgsDataSourceURI( dataSourceUri() );
497
uri.setSql( mSubsetString );
498
setDataSourceUri( uri.uri() );
505
void QgsSpatiaLiteProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
507
// preparing the SQL statement
511
QgsLogger::critical( "Read attempt on an invalid SpatiaLite data source" );
515
if ( sqliteStatement != NULL )
517
// finalizing the current SQLite statement
518
sqlite3_finalize( sqliteStatement );
519
sqliteStatement = NULL;
522
QString sql = "SELECT ROWID";
523
for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it )
525
const QgsField & fld = field( *it );
526
const QString & fieldname = fld.name();
533
sql += QString( ", AsBinary(\"%1\")" ).arg( mGeometryColumn );
535
sql += QString( " FROM \"%1\"" ).arg( mTableName );
539
if ( !rect.isEmpty() )
541
// some kind of MBR spatial filtering is required
542
whereClause = " WHERE ";
545
// we are requested to evaluate a true INTERSECT relationship
546
QString mbr = QString( "%1, %2, %3, %4" ).
547
arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
548
arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
549
arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
550
whereClause += QString( "Intersects(\"%1\", BuildMbr(%2)) AND " ).arg( mGeometryColumn ).arg( mbr );
554
// handling a VirtualShape layer
555
QString mbr = QString( "%1, %2, %3, %4" ).
556
arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
557
arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
558
arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
559
whereClause += QString( "MbrIntersects(\"%1\", BuildMbr(%2))" ).arg( mGeometryColumn ).arg( mbr );
563
if ( spatialIndexRTree )
565
// using the RTree spatial index
566
QString mbrFilter = QString( "xmin <= %1 AND " ).arg( QString::number( rect.xMaximum(), 'f', 6 ) );
567
mbrFilter += QString( "xmax >= %1 AND " ).arg( QString::number( rect.xMinimum(), 'f', 6 ) );
568
mbrFilter += QString( "ymin <= %1 AND " ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
569
mbrFilter += QString( "ymax >= %1" ).arg( QString::number( rect.yMinimum(), 'f', 6 ) );
570
QString idxName = QString( "idx_%1_%2" ).arg( mIndexTable ).arg( mIndexGeometry );
571
whereClause += QString( "ROWID IN (SELECT pkid FROM \"%1\" WHERE %2)" ).arg( idxName ).arg( mbrFilter );
573
else if ( spatialIndexMbrCache )
575
// using the MbrCache spatial index
576
QString mbr = QString( "%1, %2, %3, %4" ).
577
arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
578
arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
579
arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
580
QString idxName = QString( "cache_%1_%2" ).arg( mIndexTable ).arg( mIndexGeometry );
581
whereClause += QString( "ROWID IN (SELECT rowid FROM \"%1\" WHERE mbr = FilterMbrIntersects(%2))" ).arg( idxName ).arg( mbr );
585
// using simple MBR filtering
586
QString mbr = QString( "%1, %2, %3, %4" ).
587
arg( QString::number( rect.xMinimum(), 'f', 6 ) ).
588
arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
589
arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
590
whereClause += QString( "MbrIntersects(\"%1\", BuildMbr(%2))" ).arg( mGeometryColumn ).arg( mbr );
595
if ( !whereClause.isEmpty() )
598
if ( !mSubsetString.isEmpty() )
600
if ( !whereClause.isEmpty() )
608
sql += "( " + mSubsetString + ")";
611
mFetchGeom = fetchGeometry;
612
mAttributesToFetch = fetchAttributes;
613
if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &sqliteStatement, NULL ) != SQLITE_OK )
615
// some error occurred
616
QString errCause = sqlite3_errmsg( sqliteHandle );
617
QString msg = tr( "SQLite error: %1\n\nSQL: %2" ).arg( sql ).arg( errCause );
618
QgsLogger::critical( msg );
619
sqliteStatement = NULL;
624
QgsRectangle QgsSpatiaLiteProvider::extent()
630
size_t QgsSpatiaLiteProvider::layerCount() const
637
* Return the feature type
639
QGis::WkbType QgsSpatiaLiteProvider::geometryType() const
645
* Return the feature type
647
long QgsSpatiaLiteProvider::featureCount() const
649
return numberFeatures;
653
* Return the number of fields
655
uint QgsSpatiaLiteProvider::fieldCount() const
657
return attributeFields.size();
661
void QgsSpatiaLiteProvider::rewind()
663
if ( sqliteStatement )
665
sqlite3_finalize( sqliteStatement );
666
sqliteStatement = NULL;
671
QgsCoordinateReferenceSystem QgsSpatiaLiteProvider::crs()
673
QgsCoordinateReferenceSystem srs;
674
srs.createFromProj4( mProj4text );
679
bool QgsSpatiaLiteProvider::isValid()
685
QString QgsSpatiaLiteProvider::name() const
687
return SPATIALITE_KEY;
688
} // QgsSpatiaLiteProvider::name()
691
QString QgsSpatiaLiteProvider::description() const
693
return SPATIALITE_DESCRIPTION;
694
} // QgsSpatiaLiteProvider::description()
696
const QgsFieldMap & QgsSpatiaLiteProvider::fields() const
698
return attributeFields;
701
// Returns the minimum value of an attribute
702
QVariant QgsSpatiaLiteProvider::minimumValue( int index )
712
// get the field name
713
const QgsField & fld = field( index );
715
QString sql = QString( "SELECT Min(\"%1\") FROM \"%2\"" ).arg( fld.name() ).arg( mTableName );
717
if ( !mSubsetString.isEmpty() )
719
sql += " WHERE ( " + mSubsetString + ")";
722
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
723
if ( ret != SQLITE_OK )
729
for ( i = 1; i <= rows; i++ )
731
minValue = results[( i * columns ) + 0];
734
sqlite3_free_table( results );
736
if ( minValue.isEmpty() )
739
return QVariant( QString::null );
743
// returning as DOUBLE
744
return minValue.toDouble();
749
if ( errMsg != NULL )
751
QString error = "minValue() SQL error: ";
753
QgsLogger::critical( error );
754
sqlite3_free( errMsg );
756
return QVariant( QString::null );
759
// Returns the maximum value of an attribute
760
QVariant QgsSpatiaLiteProvider::maximumValue( int index )
770
// get the field name
771
const QgsField & fld = field( index );
773
QString sql = QString( "SELECT Max(\"%1\") FROM \"%2\"" ).arg( fld.name() ).arg( mTableName );
775
if ( !mSubsetString.isEmpty() )
777
sql += " WHERE ( " + mSubsetString + ")";
780
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
781
if ( ret != SQLITE_OK )
787
for ( i = 1; i <= rows; i++ )
789
maxValue = results[( i * columns ) + 0];
792
sqlite3_free_table( results );
794
if ( maxValue.isEmpty() )
797
return QVariant( QString::null );
801
// returning as DOUBLE
802
return maxValue.toDouble();
807
if ( errMsg != NULL )
809
QString error = "maxValue() SQL error: ";
811
QgsLogger::critical( error );
812
sqlite3_free( errMsg );
814
return QVariant( QString::null );
817
// Returns the list of unique values of an attribute
818
void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueValues, int limit )
820
sqlite3_stmt *stmt = NULL;
825
uniqueValues.clear();
827
// get the field name
828
const QgsField & fld = field( index );
830
sql = QString( "SELECT DISTINCT \"%1\" FROM \"%2\" ORDER BY \"%1\"" ).arg( fld.name() ).arg( mTableName );
832
if ( !mSubsetString.isEmpty() )
834
sql += " WHERE ( " + mSubsetString + ")";
839
sql += QString( " LIMIT %1" ).arg( limit );
842
// SQLite prepared statement
843
if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
845
// some error occurred
846
QString errCause = sqlite3_errmsg( sqliteHandle );
847
QString msg = tr( "SQLite error: %1\n\nSQL: %2" ).arg( sql ).arg( errCause );
848
QgsLogger::critical( msg );
854
// this one is an infinitive loop, intended to fetch any row
855
int ret = sqlite3_step( stmt );
857
if ( ret == SQLITE_DONE )
859
// there are no more rows to fetch - we can stop looping
863
if ( ret == SQLITE_ROW )
865
// fetching one column value
866
switch ( sqlite3_column_type( stmt, 0 ) )
869
uniqueValues.append( QString( "%1" ).arg( sqlite3_column_int( stmt, 0 ) ) );
872
uniqueValues.append( QString( "%1" ).arg( sqlite3_column_double( stmt, 0 ) ) );
875
uniqueValues.append( QString::fromUtf8(( const char * ) sqlite3_column_text( stmt, 0 ) ) );
878
uniqueValues.append( "" );
884
// some unexpected error occurred
885
const char *err = sqlite3_errmsg( sqliteHandle );
886
int len = strlen( err );
887
errMsg = ( char * ) sqlite3_malloc( len + 1 );
888
strcpy( errMsg, err );
892
sqlite3_finalize( stmt );
897
QString msg = QString( "getUniqueValues SQL error:\n%1\n" ).arg( sql );
901
sqlite3_free( errMsg );
904
msg += "unknown cause";
905
QgsLogger::critical( msg );
908
bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist )
910
sqlite3_stmt *stmt = NULL;
912
bool toCommit = false;
917
if ( flist.size() == 0 )
919
const QgsAttributeMap & attributevec = flist[0].attributeMap();
921
int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
922
if ( ret != SQLITE_OK )
924
// some error occurred
929
if ( !mPrimaryKey.isEmpty() )
931
sql = QString( "INSERT INTO \"%1\" (\"%2\", \"%3\"" ).
932
arg( mTableName ).arg( mPrimaryKey ).arg( mGeometryColumn );
933
values = QString( ") VALUES (NULL, GeomFromWKB(?, %1)" ).arg( mSrid );
937
sql = QString( "INSERT INTO \"%1\" (\"%2\"" ).arg( mTableName ).arg( mGeometryColumn );
938
values = QString( ") VALUES (GeomFromWKB(?, %1)" ).arg( mSrid );
941
for ( QgsAttributeMap::const_iterator it = attributevec.begin(); it != attributevec.end(); it++ )
943
QgsFieldMap::const_iterator fit = attributeFields.find( it.key() );
944
if ( fit == attributeFields.end() )
947
QString fieldname = fit->name();
948
if ( fieldname.isEmpty() || fieldname == mGeometryColumn || fieldname == mPrimaryKey )
960
// SQLite prepared statement
961
if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
963
// some error occurred
964
QString errCause = sqlite3_errmsg( sqliteHandle );
965
QString msg = tr( "SQLite error: %1\n\nSQL: %2" ).arg( sql ).arg( errCause );
966
QgsLogger::critical( msg );
970
for ( QgsFeatureList::iterator features = flist.begin(); features != flist.end(); features++ )
972
// looping on each feature to insert
973
const QgsAttributeMap & attributevec = features->attributeMap();
975
// resetting Prepared Statement and bindings
976
sqlite3_reset( stmt );
977
sqlite3_clear_bindings( stmt );
979
// binding GEOMETRY to Prepared Statement
980
const unsigned char *wkb = features->geometry()->asWkb();
981
sqlite3_bind_blob( stmt, 1, wkb, features->geometry()->wkbSize(), SQLITE_STATIC );
983
// initializing the column counter
986
for ( QgsAttributeMap::const_iterator it = attributevec.begin(); it != attributevec.end(); it++ )
988
// binding values for each attribute
989
QgsFieldMap::const_iterator fit = attributeFields.find( it.key() );
990
if ( fit == attributeFields.end() )
993
QString fieldname = fit->name();
994
if ( fieldname.isEmpty() || fieldname == mGeometryColumn || fieldname == mPrimaryKey )
997
QVariant::Type type = fit->type();
998
if ( it->toString().isEmpty() )
1000
// assuming to be a NULL value
1001
type = QVariant::Invalid;
1004
if ( type == QVariant::Int )
1006
// binding an INTEGER value
1007
sqlite3_bind_int( stmt, ++ia, it->toInt() );
1009
else if ( type == QVariant::Double )
1011
// binding a DOUBLE value
1012
sqlite3_bind_double( stmt, ++ia, it->toDouble() );
1014
else if ( type == QVariant::String )
1016
// binding a TEXT value
1017
QString txt = it->toString();
1018
int len = txt.toUtf8().length() + 1;
1019
char *vl = new char [len];
1020
strcpy( vl, txt.toUtf8().constData() );
1021
sqlite3_bind_text( stmt, ++ia, vl, len, SQLITE_TRANSIENT );
1026
// binding a NULL value
1027
sqlite3_bind_null( stmt, ++ia );
1031
// performing actual row insert
1032
ret = sqlite3_step( stmt );
1034
if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
1040
// some unexpected error occurred
1041
const char *err = sqlite3_errmsg( sqliteHandle );
1042
int len = strlen( err );
1043
errMsg = ( char * ) sqlite3_malloc( len + 1 );
1044
strcpy( errMsg, err );
1049
sqlite3_finalize( stmt );
1051
ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
1052
if ( ret != SQLITE_OK )
1054
// some error occurred
1060
QString msg = QString( "addFeatures SQL error:\n%1\n" ).arg( sql );
1064
sqlite3_free( errMsg );
1067
msg += "unknown cause";
1068
QgsLogger::critical( msg );
1072
// ROLLBACK after some previous error
1073
sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
1079
bool QgsSpatiaLiteProvider::deleteFeatures( const QgsFeatureIds & id )
1081
sqlite3_stmt *stmt = NULL;
1082
char *errMsg = NULL;
1083
bool toCommit = false;
1086
int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
1087
if ( ret != SQLITE_OK )
1089
// some error occurred
1094
sql = QString( "DELETE FROM \"%1\" WHERE ROWID = ?" ).arg( mTableName );
1096
// SQLite prepared statement
1097
if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
1099
// some error occurred
1100
QString errCause = sqlite3_errmsg( sqliteHandle );
1101
QString msg = tr( "SQLite error: %1\n\nSQL: %2" ).arg( sql ).arg( errCause );
1102
QgsLogger::critical( msg );
1106
for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
1108
// looping on each feature to be deleted
1109
// resetting Prepared Statement and bindings
1110
sqlite3_reset( stmt );
1111
sqlite3_clear_bindings( stmt );
1113
sqlite3_bind_int( stmt, 1, *it );
1115
// performing actual row deletion
1116
ret = sqlite3_step( stmt );
1117
if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
1123
// some unexpected error occurred
1124
const char *err = sqlite3_errmsg( sqliteHandle );
1125
int len = strlen( err );
1126
errMsg = ( char * ) sqlite3_malloc( len + 1 );
1127
strcpy( errMsg, err );
1131
sqlite3_finalize( stmt );
1133
ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
1134
if ( ret != SQLITE_OK )
1136
// some error occurred
1143
QString msg = QString( "deleteFeatures SQL error:\n%1\n" ).arg( sql );
1147
sqlite3_free( errMsg );
1150
msg += "unknown cause";
1151
QgsLogger::critical( msg );
1155
// ROLLBACK after some previous error
1156
sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
1162
bool QgsSpatiaLiteProvider::addAttributes( const QList<QgsField> &attributes )
1164
char *errMsg = NULL;
1165
bool toCommit = false;
1168
int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
1169
if ( ret != SQLITE_OK )
1171
// some error occurred
1176
for ( QList<QgsField>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter )
1178
sql = QString( "ALTER TABLE \"%1\" ADD COLUMN \"%2\" %3" )
1180
.arg( iter->name() )
1181
.arg( iter->typeName() );
1182
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), NULL, NULL, &errMsg );
1183
if ( ret != SQLITE_OK )
1185
// some error occurred
1190
ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
1191
if ( ret != SQLITE_OK )
1193
// some error occurred
1200
QString msg = QString( "addAttributes SQL error:\n%1\n" ).arg( sql );
1204
sqlite3_free( errMsg );
1207
msg += "unknown cause";
1208
QgsLogger::critical( msg );
1212
// ROLLBACK after some previous error
1213
sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
1219
bool QgsSpatiaLiteProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
1221
char *errMsg = NULL;
1222
bool toCommit = false;
1225
int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
1226
if ( ret != SQLITE_OK )
1228
// some error occurred
1233
for ( QgsChangedAttributesMap::const_iterator iter = attr_map.begin(); iter != attr_map.end(); ++iter )
1235
int fid = iter.key();
1237
// skip added features
1241
QString sql = QString( "UPDATE \"%1\" SET " ).arg( mTableName );
1244
const QgsAttributeMap & attrs = iter.value();
1246
// cycle through the changed attributes of the feature
1247
for ( QgsAttributeMap::const_iterator siter = attrs.begin(); siter != attrs.end(); ++siter )
1249
QString fieldName = field( siter.key() ).name();
1256
QVariant::Type type = siter->type();
1257
if ( siter->toString().isEmpty() )
1259
// assuming to be a NULL value
1260
type = QVariant::Invalid;
1263
if ( type == QVariant::Invalid )
1265
// binding a NULL value
1266
sql += QString( "\"%1\"=NULL" ).arg( fieldName );
1268
else if ( type == QVariant::Int || type == QVariant::Double )
1270
// binding a NUMERIC value
1271
sql += QString( "\"%1\"=%2" ).arg( fieldName ).arg( siter->toString() );
1275
// binding a TEXT value
1276
sql += QString( "\"%1\"=%2" ).arg( fieldName ).arg( quotedValue( siter->toString() ) );
1279
sql += QString( " WHERE ROWID=%1" ).arg( fid );
1281
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), NULL, NULL, &errMsg );
1282
if ( ret != SQLITE_OK )
1284
// some error occurred
1289
ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
1290
if ( ret != SQLITE_OK )
1292
// some error occurred
1299
QString msg = QString( "changeAttributeValues SQL error:\n%1\n" ).arg( sql );
1303
sqlite3_free( errMsg );
1306
msg += "unknown cause";
1307
QgsLogger::critical( msg );
1311
// ROLLBACK after some previous error
1312
sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
1318
bool QgsSpatiaLiteProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
1320
sqlite3_stmt *stmt = NULL;
1321
char *errMsg = NULL;
1322
bool toCommit = false;
1325
int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
1326
if ( ret != SQLITE_OK )
1328
// some error occurred
1334
QString( "UPDATE \"%1\" SET \"%2\" = GeomFromWKB(?, %3) WHERE ROWID = ?" ).
1335
arg( mTableName ).arg( mGeometryColumn ).arg( mSrid );
1337
// SQLite prepared statement
1338
if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
1340
// some error occurred
1341
QString errCause = sqlite3_errmsg( sqliteHandle );
1342
QString msg = tr( "SQLite error: %1\n\nSQL: %2" ).arg( sql ).arg( errCause );
1343
QgsLogger::critical( msg );
1347
for ( QgsGeometryMap::iterator iter = geometry_map.begin(); iter != geometry_map.end(); ++iter )
1349
// looping on each feature to change
1350
if ( iter->asWkb() )
1353
// resetting Prepared Statement and bindings
1354
sqlite3_reset( stmt );
1355
sqlite3_clear_bindings( stmt );
1357
// binding GEOMETRY to Prepared Statement
1358
const unsigned char *wkb = iter->asWkb();
1359
sqlite3_bind_blob( stmt, 1, wkb, iter->wkbSize(), SQLITE_STATIC );
1360
sqlite3_bind_int( stmt, 2, iter.key() );
1362
// performing actual row update
1363
ret = sqlite3_step( stmt );
1364
if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
1368
// some unexpected error occurred
1369
const char *err = sqlite3_errmsg( sqliteHandle );
1370
int len = strlen( err );
1371
errMsg = ( char * ) sqlite3_malloc( len + 1 );
1372
strcpy( errMsg, err );
1378
sqlite3_finalize( stmt );
1380
ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
1381
if ( ret != SQLITE_OK )
1383
// some error occurred
1389
QString msg = QString( "addFeatures SQL error:\n%1\n" ).arg( sql );
1393
sqlite3_free( errMsg );
1396
msg += "unknown cause";
1397
QgsLogger::critical( msg );
1401
// ROLLBACK after some previous error
1402
sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
1409
int QgsSpatiaLiteProvider::capabilities() const
1411
return enabledCapabilities;
1414
void QgsSpatiaLiteProvider::closeDb()
1416
// trying to close the SQLite DB
1417
if ( sqliteStatement )
1419
sqlite3_finalize( sqliteStatement );
1420
sqliteStatement = NULL;
1424
SqliteHandles::closeDb( handle );
1428
bool QgsSpatiaLiteProvider::SqliteHandles::checkMetadata( sqlite3 *handle )
1435
int spatial_type = 0;
1436
ret = sqlite3_get_table( handle, "SELECT CheckSpatialMetadata()", &results, &rows, &columns, NULL );
1437
if ( ret != SQLITE_OK )
1443
for ( i = 1; i <= rows; i++ )
1444
spatial_type = atoi( results[( i * columns ) + 0] );
1446
sqlite3_free_table( results );
1448
if ( spatial_type == 1 )
1453
QgsSpatiaLiteProvider::SqliteHandles * QgsSpatiaLiteProvider::SqliteHandles::openDb( const QString & dbPath )
1455
sqlite3 *sqlite_handle;
1457
QMap < QString, QgsSpatiaLiteProvider::SqliteHandles * >&handles = QgsSpatiaLiteProvider::SqliteHandles::handles;
1459
if ( handles.contains( dbPath ) )
1461
QgsDebugMsg( QString( "Using cached connection for %1" ).arg( dbPath ) );
1462
handles[dbPath]->ref++;
1463
return handles[dbPath];
1466
QgsDebugMsg( QString( "New sqlite connection for " ) + dbPath );
1467
if ( sqlite3_open_v2( dbPath.toUtf8().constData(), &sqlite_handle, SQLITE_OPEN_READWRITE, NULL ) )
1471
QString errCause = sqlite3_errmsg( sqlite_handle );
1472
QString msg = tr( "Failure while connecting to: %1\n\n%2" ).arg( dbPath ).arg( errCause );
1473
QgsLogger::critical( msg );
1477
// checking the DB for sanity
1478
if ( checkMetadata( sqlite_handle ) == false )
1482
QString errCause = tr( "invalid metadata tables" );
1483
QString msg = tr( "Failure while connecting to: %1\n\n%2" ).arg( dbPath ).arg( errCause );
1484
QgsLogger::critical( msg );
1485
sqlite3_close( sqlite_handle );
1488
// activating Foreign Key constraints
1489
sqlite3_exec( sqlite_handle, "PRAGMA foreign_keys = 1", NULL, 0, NULL );
1491
QgsDebugMsg( "Connection to the database was successful" );
1493
SqliteHandles *handle = new SqliteHandles( sqlite_handle );
1494
handles.insert( dbPath, handle );
1499
void QgsSpatiaLiteProvider::SqliteHandles::closeDb( SqliteHandles * &handle )
1501
closeDb( handles, handle );
1504
void QgsSpatiaLiteProvider::SqliteHandles::closeDb( QMap < QString, SqliteHandles * >&handles, SqliteHandles * &handle )
1506
QMap < QString, SqliteHandles * >::iterator i;
1507
for ( i = handles.begin(); i != handles.end() && i.value() != handle; i++ )
1510
assert( i.value() == handle );
1511
assert( i.value()->ref > 0 );
1513
if ( --i.value()->ref == 0 )
1515
i.value()->sqliteClose();
1517
handles.remove( i.key() );
1523
void QgsSpatiaLiteProvider::SqliteHandles::sqliteClose()
1525
if ( sqlite_handle )
1527
sqlite3_close( sqlite_handle );
1528
sqlite_handle = NULL;
1532
QString QgsSpatiaLiteProvider::quotedValue( QString value ) const
1534
if ( value.isNull() )
1537
value.replace( "'", "''" );
1538
return value.prepend( "'" ).append( "'" );
1541
bool QgsSpatiaLiteProvider::checkLayerType()
1548
char *errMsg = NULL;
1551
mTableBased = false;
1553
mVShapeBased = false;
1555
// checking if this one is a Table-based layer
1556
QString sql = QString( "SELECT read_only FROM geometry_columns "
1557
"LEFT JOIN geometry_columns_auth "
1558
"USING (f_table_name, f_geometry_column) "
1559
"WHERE f_table_name=%1 and f_geometry_column=%2" ).arg( quotedValue( mTableName ) ).
1560
arg( quotedValue( mGeometryColumn ) );
1562
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
1563
if ( ret != SQLITE_OK )
1571
for ( i = 1; i <= rows; i++ )
1573
if ( results[( i * columns ) + 0] != NULL )
1575
if ( atoi( results[( i * columns ) + 0] ) != 0 )
1581
sqlite3_free_table( results );
1583
// checking if this one is a View-based layer
1584
sql = QString( "SELECT view_name, view_geometry FROM views_geometry_columns"
1585
" WHERE view_name=%1 and view_geometry=%2" ).arg( quotedValue( mTableName ) ).
1586
arg( quotedValue( mGeometryColumn ) );
1588
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
1589
if ( ret != SQLITE_OK )
1599
sqlite3_free_table( results );
1601
// checking if this one is a VirtualShapefile-based layer
1602
sql = QString( "SELECT virt_name, virt_geometry FROM virts_geometry_columns"
1603
" WHERE virt_name=%1 and virt_geometry=%2" ).arg( quotedValue( mTableName ) ).
1604
arg( quotedValue( mGeometryColumn ) );
1606
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
1607
if ( ret != SQLITE_OK )
1613
mVShapeBased = true;
1617
sqlite3_free_table( results );
1619
// cheching for validity
1627
if ( errMsg != NULL )
1629
QString errCause = errMsg;
1630
QString msg = QString( "checkLayerType SQL error: %1\n\n%2" ).arg( sql ).arg( errCause );
1631
QgsLogger::critical( msg );
1632
sqlite3_free( errMsg );
1637
bool QgsSpatiaLiteProvider::getGeometryDetails()
1641
ret = getTableGeometryDetails();
1643
ret = getViewGeometryDetails();
1645
ret = getVShapeGeometryDetails();
1649
bool QgsSpatiaLiteProvider::getTableGeometryDetails()
1656
char *errMsg = NULL;
1658
mIndexTable = mTableName;
1659
mIndexGeometry = mGeometryColumn;
1661
QString sql = QString( "SELECT type, srid, spatial_index_enabled FROM geometry_columns"
1662
" WHERE f_table_name=%1 and f_geometry_column=%2" ).arg( quotedValue( mTableName ) ).
1663
arg( quotedValue( mGeometryColumn ) );
1665
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
1666
if ( ret != SQLITE_OK )
1672
for ( i = 1; i <= rows; i++ )
1674
QString fType = results[( i * columns ) + 0];
1675
QString xSrid = results[( i * columns ) + 1];
1676
QString spatialIndex = results[( i * columns ) + 2];
1678
if ( fType == "POINT" )
1680
geomType = QGis::WKBPoint;
1682
else if ( fType == "MULTIPOINT" )
1684
geomType = QGis::WKBMultiPoint;
1686
else if ( fType == "LINESTRING" )
1688
geomType = QGis::WKBLineString;
1690
else if ( fType == "MULTILINESTRING" )
1692
geomType = QGis::WKBMultiLineString;
1694
else if ( fType == "POLYGON" )
1696
geomType = QGis::WKBPolygon;
1698
else if ( fType == "MULTIPOLYGON" )
1700
geomType = QGis::WKBMultiPolygon;
1702
mSrid = xSrid.toInt();
1703
if ( spatialIndex.toInt() == 1 )
1705
spatialIndexRTree = true;
1707
if ( spatialIndex.toInt() == 2 )
1709
spatialIndexMbrCache = true;
1714
sqlite3_free_table( results );
1716
if ( geomType == QGis::WKBUnknown || mSrid < 0 )
1719
return getSridDetails();
1723
if ( errMsg != NULL )
1725
QString errCause = errMsg;
1726
QString msg = QString( "getTableGeometryDetails SQL error: %1\n\n%2" ).arg( sql ).arg( errCause );
1727
QgsLogger::critical( msg );
1728
sqlite3_free( errMsg );
1733
bool QgsSpatiaLiteProvider::getViewGeometryDetails()
1740
char *errMsg = NULL;
1742
QString sql = QString( "SELECT type, srid, spatial_index_enabled, f_table_name, f_geometry_column "
1743
" FROM views_geometry_columns"
1744
" JOIN geometry_columns USING (f_table_name, f_geometry_column)"
1745
" WHERE view_name=%1 and view_geometry=%2" ).arg( quotedValue( mTableName ) ).
1746
arg( quotedValue( mGeometryColumn ) );
1748
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
1749
if ( ret != SQLITE_OK )
1755
for ( i = 1; i <= rows; i++ )
1757
QString fType = results[( i * columns ) + 0];
1758
QString xSrid = results[( i * columns ) + 1];
1759
QString spatialIndex = results[( i * columns ) + 2];
1760
mIndexTable = results[( i * columns ) + 3];
1761
mIndexGeometry = results[( i * columns ) + 4];
1763
if ( fType == "POINT" )
1765
geomType = QGis::WKBPoint;
1767
else if ( fType == "MULTIPOINT" )
1769
geomType = QGis::WKBMultiPoint;
1771
else if ( fType == "LINESTRING" )
1773
geomType = QGis::WKBLineString;
1775
else if ( fType == "MULTILINESTRING" )
1777
geomType = QGis::WKBMultiLineString;
1779
else if ( fType == "POLYGON" )
1781
geomType = QGis::WKBPolygon;
1783
else if ( fType == "MULTIPOLYGON" )
1785
geomType = QGis::WKBMultiPolygon;
1787
mSrid = xSrid.toInt();
1788
if ( spatialIndex.toInt() == 1 )
1790
spatialIndexRTree = true;
1792
if ( spatialIndex.toInt() == 2 )
1794
spatialIndexMbrCache = true;
1799
sqlite3_free_table( results );
1801
if ( geomType == QGis::WKBUnknown || mSrid < 0 )
1804
return getSridDetails();
1808
if ( errMsg != NULL )
1810
QString errCause = errMsg;
1811
QString msg = QString( "getViewGeometryDetails SQL error: %1\n\n%2" ).arg( sql ).arg( errCause );
1812
QgsLogger::critical( msg );
1813
sqlite3_free( errMsg );
1818
bool QgsSpatiaLiteProvider::getVShapeGeometryDetails()
1825
char *errMsg = NULL;
1827
QString sql = QString( "SELECT type, srid FROM virts_geometry_columns"
1828
" WHERE virt_name=%1 and virt_geometry=%2" ).arg( quotedValue( mTableName ) ).
1829
arg( quotedValue( mGeometryColumn ) );
1831
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
1832
if ( ret != SQLITE_OK )
1838
for ( i = 1; i <= rows; i++ )
1840
QString fType = results[( i * columns ) + 0];
1841
QString xSrid = results[( i * columns ) + 1];
1843
if ( fType == "POINT" )
1845
geomType = QGis::WKBPoint;
1847
else if ( fType == "MULTIPOINT" )
1849
geomType = QGis::WKBMultiPoint;
1851
else if ( fType == "LINESTRING" )
1853
geomType = QGis::WKBLineString;
1855
else if ( fType == "MULTILINESTRING" )
1857
geomType = QGis::WKBMultiLineString;
1859
else if ( fType == "POLYGON" )
1861
geomType = QGis::WKBPolygon;
1863
else if ( fType == "MULTIPOLYGON" )
1865
geomType = QGis::WKBMultiPolygon;
1867
mSrid = xSrid.toInt();
1871
sqlite3_free_table( results );
1873
if ( geomType == QGis::WKBUnknown || mSrid < 0 )
1876
return getSridDetails();
1880
if ( errMsg != NULL )
1882
QString errCause = errMsg;
1883
QString msg = QString( "getVShapeGeometryDetails SQL error: %1\n\n%2" ).arg( sql ).arg( errCause );
1884
QgsLogger::critical( msg );
1885
sqlite3_free( errMsg );
1890
bool QgsSpatiaLiteProvider::getSridDetails()
1897
char *errMsg = NULL;
1899
QString sql = QString( "SELECT proj4text FROM spatial_ref_sys WHERE srid=%1" ).arg( mSrid );
1901
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
1902
if ( ret != SQLITE_OK )
1908
for ( i = 1; i <= rows; i++ )
1910
mProj4text = results[( i * columns ) + 0];
1913
sqlite3_free_table( results );
1919
if ( errMsg != NULL )
1921
QString errCause = errMsg;
1922
QString msg = QString( "getSridDetails SQL error: %1\n\n%2" ).arg( sql ).arg( errCause );
1923
QgsLogger::critical( msg );
1924
sqlite3_free( errMsg );
1929
bool QgsSpatiaLiteProvider::getTableSummary()
1936
char *errMsg = NULL;
1938
QString sql = QString( "SELECT Min(MbrMinX(\"%1\")), Min(MbrMinY(\"%1\")), "
1939
"Max(MbrMaxX(\"%1\")), Max(MbrMaxY(\"%1\")), Count(*) " "FROM \"%2\"" ).arg( mGeometryColumn ).arg( mTableName );
1941
if ( !mSubsetString.isEmpty() )
1943
sql += " WHERE ( " + mSubsetString + ")";
1946
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
1947
if ( ret != SQLITE_OK )
1953
for ( i = 1; i <= rows; i++ )
1955
QString minX = results[( i * columns ) + 0];
1956
QString minY = results[( i * columns ) + 1];
1957
QString maxX = results[( i * columns ) + 2];
1958
QString maxY = results[( i * columns ) + 3];
1959
QString count = results[( i * columns ) + 4];
1961
layerExtent.set( minX.toDouble(), minY.toDouble(), maxX.toDouble(), maxY.toDouble() );
1962
numberFeatures = count.toLong();
1965
sqlite3_free_table( results );
1970
if ( errMsg != NULL )
1972
QString error = "getTableSummary() SQL error: ";
1974
QgsLogger::critical( error );
1975
sqlite3_free( errMsg );
1980
const QgsField & QgsSpatiaLiteProvider::field( int index ) const
1982
QgsFieldMap::const_iterator it = attributeFields.find( index );
1984
if ( it == attributeFields.constEnd() )
1986
QgsLogger::critical( "Field " + QString::number( index ) + " not found." );
1995
* Class factory to return a pointer to a newly created
1996
* QgsSpatiaLiteProvider object
1998
QGISEXTERN QgsSpatiaLiteProvider *classFactory( const QString * uri )
2000
return new QgsSpatiaLiteProvider( *uri );
2003
/** Required key function (used to map the plugin to a data store type)
2005
QGISEXTERN QString providerKey()
2007
return SPATIALITE_KEY;
2011
* Required description function
2013
QGISEXTERN QString description()
2015
return SPATIALITE_DESCRIPTION;
2019
* Required isProvider function. Used to determine if this shared library
2020
* is a data provider plugin
2022
QGISEXTERN bool isProvider()