~ubuntu-branches/ubuntu/saucy/qgis/saucy

« back to all changes in this revision

Viewing changes to src/providers/spatialite/qgsspatialiteprovider.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
           qgsspatialiteprovider.cpp Data provider for SpatiaLite DBMS
 
3
begin                : Dec, 2008
 
4
copyright            : (C) 2008 Sandro Furieri
 
5
email                : a.furieri@lqt.it
 
6
 ***************************************************************************/
 
7
 
 
8
/***************************************************************************
 
9
 *                                                                         *
 
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.                                   *
 
14
 *                                                                         *
 
15
 ***************************************************************************/
 
16
 
 
17
#include <cassert>
 
18
 
 
19
#include <qgis.h>
 
20
#include <qgsapplication.h>
 
21
#include <qgsfeature.h>
 
22
#include <qgsfield.h>
 
23
#include <qgsgeometry.h>
 
24
#include <qgsmessageoutput.h>
 
25
#include <qgsrectangle.h>
 
26
#include <qgscoordinatereferencesystem.h>
 
27
 
 
28
#include "qgsprovidercountcalcevent.h"
 
29
#include "qgsproviderextentcalcevent.h"
 
30
 
 
31
#include "qgsspatialiteprovider.h"
 
32
 
 
33
#include "qgslogger.h"
 
34
 
 
35
#ifdef _MSC_VER
 
36
#define strcasecmp(a,b) stricmp(a,b)
 
37
#endif
 
38
 
 
39
const QString SPATIALITE_KEY = "spatialite";
 
40
const QString SPATIALITE_DESCRIPTION = "SpatiaLite data provider";
 
41
 
 
42
QMap < QString, QgsSpatiaLiteProvider::SqliteHandles * >QgsSpatiaLiteProvider::SqliteHandles::handles;
 
43
 
 
44
QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri ): QgsVectorDataProvider( uri ),
 
45
    geomType( QGis::WKBUnknown ), sqliteHandle( NULL ), sqliteStatement( NULL ), mSrid( -1 ), spatialIndexRTree( false ), spatialIndexMbrCache( false )
 
46
{
 
47
  QgsDataSourceURI anUri = QgsDataSourceURI( uri );
 
48
 
 
49
  // parsing members from the uri structure
 
50
  mTableName = anUri.table();
 
51
  mGeometryColumn = anUri.geometryColumn();
 
52
  mSqlitePath = anUri.database();
 
53
  mSubsetString = anUri.sql();
 
54
 
 
55
  // trying to open the SQLite DB
 
56
  spatialite_init( 0 );
 
57
  valid = true;
 
58
  handle = SqliteHandles::openDb( mSqlitePath );
 
59
  if ( handle == NULL )
 
60
  {
 
61
    valid = false;
 
62
    return;
 
63
  }
 
64
  sqliteHandle = handle->handle();
 
65
 
 
66
  if ( !checkLayerType() )  // check if this one Layer is based on a Table, View or VirtualShapefile
 
67
  {
 
68
    // invalid metadata
 
69
    numberFeatures = 0;
 
70
    valid = false;
 
71
 
 
72
    QgsLogger::critical( "Invalid SpatiaLite layer" );
 
73
    closeDb();
 
74
    return;
 
75
  }
 
76
  enabledCapabilities = QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::SelectGeometryAtId;
 
77
  if ( mTableBased && !mReadOnly )
 
78
  {
 
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;
 
85
  }
 
86
 
 
87
  if ( !getGeometryDetails() )  // gets srid and geometry type
 
88
  {
 
89
    // the table is not a geometry table
 
90
    numberFeatures = 0;
 
91
    valid = false;
 
92
 
 
93
    QgsLogger::critical( "Invalid SpatiaLite layer" );
 
94
    closeDb();
 
95
    return;
 
96
  }
 
97
  if ( !getTableSummary() )     // gets the extent and feature count
 
98
  {
 
99
    numberFeatures = 0;
 
100
    valid = false;
 
101
 
 
102
    QgsLogger::critical( "Invalid SpatiaLite layer" );
 
103
    closeDb();
 
104
    return;
 
105
  }
 
106
  // load the columns list
 
107
  loadFields();
 
108
  if ( sqliteHandle == NULL )
 
109
  {
 
110
    valid = false;
 
111
 
 
112
    QgsLogger::critical( "Invalid SpatiaLite layer" );
 
113
    return;
 
114
  }
 
115
  //fill type names into sets
 
116
  mNativeTypes
 
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 )
 
121
  ;
 
122
}
 
123
 
 
124
QgsSpatiaLiteProvider::~QgsSpatiaLiteProvider()
 
125
{
 
126
  closeDb();
 
127
}
 
128
 
 
129
void QgsSpatiaLiteProvider::loadFields()
 
130
{
 
131
  int ret;
 
132
  int i;
 
133
  char **results;
 
134
  int rows;
 
135
  int columns;
 
136
  char *errMsg = NULL;
 
137
  QString pkName;
 
138
  int pkCount = 0;
 
139
  int fldNo = 0;
 
140
 
 
141
  attributeFields.clear();
 
142
  mPrimaryKey.clear();
 
143
 
 
144
  QString sql = QString( "PRAGMA table_info(\"%1\")" ).arg( mTableName );
 
145
 
 
146
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
147
  if ( ret != SQLITE_OK )
 
148
    goto error;
 
149
  if ( rows < 1 )
 
150
    ;
 
151
  else
 
152
  {
 
153
    for ( i = 1; i <= rows; i++ )
 
154
    {
 
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 )
 
159
      {
 
160
        // found a Primary Key column
 
161
        pkCount++;
 
162
        pkName = name;
 
163
      }
 
164
 
 
165
      if ( name != mGeometryColumn )
 
166
      {
 
167
        // for sure any SQLite value can be represented as SQLITE_TEXT
 
168
        QVariant::Type fieldType = QVariant::String;
 
169
 
 
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 )
 
175
        {
 
176
          fieldType = QVariant::Int;
 
177
        }
 
178
        else if ( strcasecmp( type, "real" ) == 0 ||
 
179
                  strcasecmp( type, "double" ) == 0 ||
 
180
                  strcasecmp( type, "double precision" ) == 0 || strcasecmp( type, "float" ) == 0 )
 
181
        {
 
182
          fieldType = QVariant::Double;
 
183
        }
 
184
 
 
185
        attributeFields.insert( fldNo++, QgsField( name, fieldType, type, 0, 0, "" ) );
 
186
      }
 
187
    }
 
188
  }
 
189
  sqlite3_free_table( results );
 
190
 
 
191
  if ( pkCount == 1 )
 
192
  {
 
193
    // setting the Primary Key column name
 
194
    mPrimaryKey = pkName;
 
195
  }
 
196
 
 
197
  return;
 
198
 
 
199
error:
 
200
  // unexpected error
 
201
  if ( errMsg != NULL )
 
202
  {
 
203
    QString error = "loadFields() SQL error: ";
 
204
    error = errMsg;
 
205
    QgsLogger::critical( error );
 
206
    sqlite3_free( errMsg );
 
207
  }
 
208
}
 
209
 
 
210
 
 
211
QString QgsSpatiaLiteProvider::storageType() const
 
212
{
 
213
  return "SQLite database with SpatiaLite extension";
 
214
}
 
215
 
 
216
 
 
217
bool QgsSpatiaLiteProvider::featureAtId( int featureId, QgsFeature & feature, bool fetchGeometry, QgsAttributeList fetchAttributes )
 
218
{
 
219
  sqlite3_stmt *stmt = NULL;
 
220
 
 
221
  QString sql = "SELECT ROWID";
 
222
  for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it )
 
223
  {
 
224
    const QgsField & fld = field( *it );
 
225
    const QString & fieldname = fld.name();
 
226
    sql += ", \"";
 
227
    sql += fieldname;
 
228
    sql += "\"";
 
229
  }
 
230
  if ( fetchGeometry )
 
231
  {
 
232
    sql += QString( ", AsBinary(\"%1\")" ).arg( mGeometryColumn );
 
233
  }
 
234
  sql += QString( " FROM \"%1\" WHERE ROWID = %2" ).arg( mTableName ).arg( featureId );
 
235
 
 
236
  if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
 
237
  {
 
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 );
 
242
    return false;
 
243
  }
 
244
 
 
245
  int ret = sqlite3_step( stmt );
 
246
  if ( ret == SQLITE_DONE )
 
247
  {
 
248
    // there are no more rows to fetch - we can stop looping destroying the SQLite statement
 
249
    sqlite3_finalize( stmt );
 
250
    return false;
 
251
  }
 
252
  if ( ret == SQLITE_ROW )
 
253
  {
 
254
    // one valid row has been fetched from the result set
 
255
    if ( !mFetchGeom )
 
256
    {
 
257
      // no geometry was required
 
258
      feature.setGeometryAndOwnership( 0, 0 );
 
259
    }
 
260
 
 
261
    int ic;
 
262
    int n_columns = sqlite3_column_count( stmt );
 
263
    for ( ic = 0; ic < n_columns; ic++ )
 
264
    {
 
265
      if ( ic == 0 )
 
266
      {
 
267
        // first column always contains the ROWID
 
268
        feature.setFeatureId( sqlite3_column_int( stmt, ic ) );
 
269
      }
 
270
      else
 
271
      {
 
272
        // iterate attributes
 
273
        bool fetched = false;
 
274
        int nAttr = 1;
 
275
        for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); it++ )
 
276
        {
 
277
          if ( nAttr == ic )
 
278
          {
 
279
            // ok, this one is the corresponding attribure
 
280
            if ( sqlite3_column_type( stmt, ic ) == SQLITE_INTEGER )
 
281
            {
 
282
              // INTEGER value
 
283
              feature.addAttribute( *it, sqlite3_column_int( stmt, ic ) );
 
284
              fetched = true;
 
285
            }
 
286
            else if ( sqlite3_column_type( stmt, ic ) == SQLITE_FLOAT )
 
287
            {
 
288
              // DOUBLE value
 
289
              feature.addAttribute( *it, sqlite3_column_double( stmt, ic ) );
 
290
              fetched = true;
 
291
            }
 
292
            else if ( sqlite3_column_type( stmt, ic ) == SQLITE_TEXT )
 
293
            {
 
294
              // TEXT value
 
295
              const char *txt = ( const char * ) sqlite3_column_text( stmt, ic );
 
296
              QString str = QString::fromUtf8( txt );
 
297
              feature.addAttribute( *it, str );
 
298
              fetched = true;
 
299
            }
 
300
            else
 
301
            {
 
302
              // assuming NULL
 
303
              feature.addAttribute( *it, QVariant( QString::null ) );
 
304
              fetched = true;
 
305
            }
 
306
          }
 
307
          nAttr++;
 
308
        }
 
309
        if ( fetched )
 
310
        {
 
311
          continue;
 
312
        }
 
313
        if ( mFetchGeom )
 
314
        {
 
315
          QString geoCol = QString( "AsBinary(\"%1\")" ).arg( mGeometryColumn );
 
316
          if ( strcasecmp( geoCol.toUtf8().constData(), sqlite3_column_name( stmt, ic ) ) == 0 )
 
317
          {
 
318
            if ( sqlite3_column_type( stmt, ic ) == SQLITE_BLOB )
 
319
            {
 
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 );
 
326
            }
 
327
            else
 
328
            {
 
329
              // NULL geometry
 
330
              feature.setGeometryAndOwnership( 0, 0 );
 
331
            }
 
332
          }
 
333
        }
 
334
      }
 
335
    }
 
336
  }
 
337
  else
 
338
  {
 
339
    // some unexpected error occurred
 
340
    QString error = "sqlite3_step() error: ";
 
341
    error += sqlite3_errmsg( sqliteHandle );
 
342
    QgsLogger::critical( error );
 
343
    sqlite3_finalize( stmt );
 
344
    return false;
 
345
  }
 
346
  sqlite3_finalize( stmt );
 
347
 
 
348
  return true;
 
349
}
 
350
 
 
351
bool QgsSpatiaLiteProvider::nextFeature( QgsFeature & feature )
 
352
{
 
353
  feature.setValid( false );
 
354
  if ( !valid )
 
355
  {
 
356
    QgsLogger::critical( "Read attempt on an invalid SpatiaLite data source" );
 
357
    return false;
 
358
  }
 
359
 
 
360
  if ( sqliteStatement == NULL )
 
361
  {
 
362
    QgsLogger::critical( "Invalid current SQLite statement" );
 
363
    return false;
 
364
  }
 
365
 
 
366
  int ret = sqlite3_step( sqliteStatement );
 
367
  if ( ret == SQLITE_DONE )
 
368
  {
 
369
    // there are no more rows to fetch - we can stop looping destroying the SQLite statement
 
370
    sqlite3_finalize( sqliteStatement );
 
371
    sqliteStatement = NULL;
 
372
    return false;
 
373
  }
 
374
  if ( ret == SQLITE_ROW )
 
375
  {
 
376
    // one valid row has been fetched from the result set
 
377
    if ( !mFetchGeom )
 
378
    {
 
379
      // no geometry was required
 
380
      feature.setGeometryAndOwnership( 0, 0 );
 
381
    }
 
382
 
 
383
    int ic;
 
384
    int n_columns = sqlite3_column_count( sqliteStatement );
 
385
    for ( ic = 0; ic < n_columns; ic++ )
 
386
    {
 
387
      if ( ic == 0 )
 
388
      {
 
389
        // first column always contains the ROWID
 
390
        feature.setFeatureId( sqlite3_column_int( sqliteStatement, ic ) );
 
391
      }
 
392
      else
 
393
      {
 
394
        // iterate attributes
 
395
        bool fetched = false;
 
396
        int nAttr = 1;
 
397
        for ( QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin(); it != mAttributesToFetch.constEnd(); it++ )
 
398
        {
 
399
          if ( nAttr == ic )
 
400
          {
 
401
            // ok, this one is the corresponding attribure
 
402
            if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_INTEGER )
 
403
            {
 
404
              // INTEGER value
 
405
              feature.addAttribute( *it, sqlite3_column_int( sqliteStatement, ic ) );
 
406
              fetched = true;
 
407
            }
 
408
            else if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_FLOAT )
 
409
            {
 
410
              // DOUBLE value
 
411
              feature.addAttribute( *it, sqlite3_column_double( sqliteStatement, ic ) );
 
412
              fetched = true;
 
413
            }
 
414
            else if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_TEXT )
 
415
            {
 
416
              // TEXT value
 
417
              const char *txt = ( const char * ) sqlite3_column_text( sqliteStatement, ic );
 
418
              QString str = QString::fromUtf8( txt );
 
419
              feature.addAttribute( *it, str );
 
420
              fetched = true;
 
421
            }
 
422
            else
 
423
            {
 
424
              // assuming NULL
 
425
              feature.addAttribute( *it, QVariant( QString::null ) );
 
426
              fetched = true;
 
427
            }
 
428
          }
 
429
          nAttr++;
 
430
        }
 
431
        if ( fetched )
 
432
        {
 
433
          continue;
 
434
        }
 
435
        if ( mFetchGeom )
 
436
        {
 
437
          QString geoCol = QString( "AsBinary(\"%1\")" ).arg( mGeometryColumn );
 
438
          if ( strcasecmp( geoCol.toUtf8().constData(), sqlite3_column_name( sqliteStatement, ic ) ) == 0 )
 
439
          {
 
440
            if ( sqlite3_column_type( sqliteStatement, ic ) == SQLITE_BLOB )
 
441
            {
 
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 );
 
448
            }
 
449
            else
 
450
            {
 
451
              // NULL geometry
 
452
              feature.setGeometryAndOwnership( 0, 0 );
 
453
            }
 
454
          }
 
455
        }
 
456
      }
 
457
    }
 
458
  }
 
459
  else
 
460
  {
 
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;
 
467
    return false;
 
468
  }
 
469
 
 
470
  feature.setValid( true );
 
471
  return true;
 
472
}
 
473
 
 
474
QString QgsSpatiaLiteProvider::subsetString()
 
475
{
 
476
  return mSubsetString;
 
477
}
 
478
 
 
479
bool QgsSpatiaLiteProvider::setSubsetString( QString theSQL )
 
480
{
 
481
  QString prevSubsetString = mSubsetString;
 
482
  mSubsetString = theSQL;
 
483
 
 
484
  // update URI
 
485
  QgsDataSourceURI uri = QgsDataSourceURI( dataSourceUri() );
 
486
  uri.setSql( mSubsetString );
 
487
  setDataSourceUri( uri.uri() );
 
488
 
 
489
  // update feature count and extents
 
490
  if ( getTableSummary() )
 
491
    return true;
 
492
 
 
493
  mSubsetString = prevSubsetString;
 
494
 
 
495
  // restore URI
 
496
  uri = QgsDataSourceURI( dataSourceUri() );
 
497
  uri.setSql( mSubsetString );
 
498
  setDataSourceUri( uri.uri() );
 
499
 
 
500
  getTableSummary();
 
501
 
 
502
  return false;
 
503
}
 
504
 
 
505
void QgsSpatiaLiteProvider::select( QgsAttributeList fetchAttributes, QgsRectangle rect, bool fetchGeometry, bool useIntersect )
 
506
{
 
507
// preparing the SQL statement
 
508
 
 
509
  if ( !valid )
 
510
  {
 
511
    QgsLogger::critical( "Read attempt on an invalid SpatiaLite data source" );
 
512
    return;
 
513
  }
 
514
 
 
515
  if ( sqliteStatement != NULL )
 
516
  {
 
517
    // finalizing the current SQLite statement
 
518
    sqlite3_finalize( sqliteStatement );
 
519
    sqliteStatement = NULL;
 
520
  }
 
521
 
 
522
  QString sql = "SELECT ROWID";
 
523
  for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it )
 
524
  {
 
525
    const QgsField & fld = field( *it );
 
526
    const QString & fieldname = fld.name();
 
527
    sql += ", \"";
 
528
    sql += fieldname;
 
529
    sql += "\"";
 
530
  }
 
531
  if ( fetchGeometry )
 
532
  {
 
533
    sql += QString( ", AsBinary(\"%1\")" ).arg( mGeometryColumn );
 
534
  }
 
535
  sql += QString( " FROM \"%1\"" ).arg( mTableName );
 
536
 
 
537
  QString whereClause;
 
538
 
 
539
  if ( !rect.isEmpty() )
 
540
  {
 
541
    // some kind of MBR spatial filtering is required
 
542
    whereClause = " WHERE ";
 
543
    if ( useIntersect )
 
544
    {
 
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 );
 
551
    }
 
552
    if ( mVShapeBased )
 
553
    {
 
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 );
 
560
    }
 
561
    else
 
562
    {
 
563
      if ( spatialIndexRTree )
 
564
      {
 
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 );
 
572
      }
 
573
      else if ( spatialIndexMbrCache )
 
574
      {
 
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 );
 
582
      }
 
583
      else
 
584
      {
 
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 );
 
591
      }
 
592
    }
 
593
  }
 
594
 
 
595
  if ( !whereClause.isEmpty() )
 
596
    sql += whereClause;
 
597
 
 
598
  if ( !mSubsetString.isEmpty() )
 
599
  {
 
600
    if ( !whereClause.isEmpty() )
 
601
    {
 
602
      sql += " AND ";
 
603
    }
 
604
    else
 
605
    {
 
606
      sql += " WHERE ";
 
607
    }
 
608
    sql += "( " + mSubsetString + ")";
 
609
  }
 
610
 
 
611
  mFetchGeom = fetchGeometry;
 
612
  mAttributesToFetch = fetchAttributes;
 
613
  if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &sqliteStatement, NULL ) != SQLITE_OK )
 
614
  {
 
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;
 
620
  }
 
621
}
 
622
 
 
623
 
 
624
QgsRectangle QgsSpatiaLiteProvider::extent()
 
625
{
 
626
  return layerExtent;
 
627
}
 
628
 
 
629
 
 
630
size_t QgsSpatiaLiteProvider::layerCount() const
 
631
{
 
632
  return 1;
 
633
}
 
634
 
 
635
 
 
636
/**
 
637
 * Return the feature type
 
638
 */
 
639
QGis::WkbType QgsSpatiaLiteProvider::geometryType() const
 
640
{
 
641
  return geomType;
 
642
}
 
643
 
 
644
/**
 
645
 * Return the feature type
 
646
 */
 
647
long QgsSpatiaLiteProvider::featureCount() const
 
648
{
 
649
  return numberFeatures;
 
650
}
 
651
 
 
652
/**
 
653
 * Return the number of fields
 
654
 */
 
655
uint QgsSpatiaLiteProvider::fieldCount() const
 
656
{
 
657
  return attributeFields.size();
 
658
}
 
659
 
 
660
 
 
661
void QgsSpatiaLiteProvider::rewind()
 
662
{
 
663
  if ( sqliteStatement )
 
664
  {
 
665
    sqlite3_finalize( sqliteStatement );
 
666
    sqliteStatement = NULL;
 
667
  }
 
668
  loadFields();
 
669
}
 
670
 
 
671
QgsCoordinateReferenceSystem QgsSpatiaLiteProvider::crs()
 
672
{
 
673
  QgsCoordinateReferenceSystem srs;
 
674
  srs.createFromProj4( mProj4text );
 
675
  return srs;
 
676
}
 
677
 
 
678
 
 
679
bool QgsSpatiaLiteProvider::isValid()
 
680
{
 
681
  return valid;
 
682
}
 
683
 
 
684
 
 
685
QString QgsSpatiaLiteProvider::name() const
 
686
{
 
687
  return SPATIALITE_KEY;
 
688
}                               //  QgsSpatiaLiteProvider::name()
 
689
 
 
690
 
 
691
QString QgsSpatiaLiteProvider::description() const
 
692
{
 
693
  return SPATIALITE_DESCRIPTION;
 
694
}                               //  QgsSpatiaLiteProvider::description()
 
695
 
 
696
const QgsFieldMap & QgsSpatiaLiteProvider::fields() const
 
697
{
 
698
  return attributeFields;
 
699
}
 
700
 
 
701
// Returns the minimum value of an attribute
 
702
QVariant QgsSpatiaLiteProvider::minimumValue( int index )
 
703
{
 
704
  int ret;
 
705
  int i;
 
706
  char **results;
 
707
  int rows;
 
708
  int columns;
 
709
  char *errMsg = NULL;
 
710
  QString minValue;
 
711
 
 
712
  // get the field name
 
713
  const QgsField & fld = field( index );
 
714
 
 
715
  QString sql = QString( "SELECT Min(\"%1\") FROM \"%2\"" ).arg( fld.name() ).arg( mTableName );
 
716
 
 
717
  if ( !mSubsetString.isEmpty() )
 
718
  {
 
719
    sql += " WHERE ( " + mSubsetString + ")";
 
720
  }
 
721
 
 
722
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
723
  if ( ret != SQLITE_OK )
 
724
    goto error;
 
725
  if ( rows < 1 )
 
726
    ;
 
727
  else
 
728
  {
 
729
    for ( i = 1; i <= rows; i++ )
 
730
    {
 
731
      minValue = results[( i * columns ) + 0];
 
732
    }
 
733
  }
 
734
  sqlite3_free_table( results );
 
735
 
 
736
  if ( minValue.isEmpty() )
 
737
  {
 
738
    // NULL or not found
 
739
    return QVariant( QString::null );
 
740
  }
 
741
  else
 
742
  {
 
743
    // returning as DOUBLE
 
744
    return minValue.toDouble();
 
745
  }
 
746
 
 
747
error:
 
748
  // unexpected error
 
749
  if ( errMsg != NULL )
 
750
  {
 
751
    QString error = "minValue() SQL error: ";
 
752
    error = errMsg;
 
753
    QgsLogger::critical( error );
 
754
    sqlite3_free( errMsg );
 
755
  }
 
756
  return QVariant( QString::null );
 
757
}
 
758
 
 
759
// Returns the maximum value of an attribute
 
760
QVariant QgsSpatiaLiteProvider::maximumValue( int index )
 
761
{
 
762
  int ret;
 
763
  int i;
 
764
  char **results;
 
765
  int rows;
 
766
  int columns;
 
767
  char *errMsg = NULL;
 
768
  QString maxValue;
 
769
 
 
770
  // get the field name
 
771
  const QgsField & fld = field( index );
 
772
 
 
773
  QString sql = QString( "SELECT Max(\"%1\") FROM \"%2\"" ).arg( fld.name() ).arg( mTableName );
 
774
 
 
775
  if ( !mSubsetString.isEmpty() )
 
776
  {
 
777
    sql += " WHERE ( " + mSubsetString + ")";
 
778
  }
 
779
 
 
780
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
781
  if ( ret != SQLITE_OK )
 
782
    goto error;
 
783
  if ( rows < 1 )
 
784
    ;
 
785
  else
 
786
  {
 
787
    for ( i = 1; i <= rows; i++ )
 
788
    {
 
789
      maxValue = results[( i * columns ) + 0];
 
790
    }
 
791
  }
 
792
  sqlite3_free_table( results );
 
793
 
 
794
  if ( maxValue.isEmpty() )
 
795
  {
 
796
    // NULL or not found
 
797
    return QVariant( QString::null );
 
798
  }
 
799
  else
 
800
  {
 
801
    // returning as DOUBLE
 
802
    return maxValue.toDouble();
 
803
  }
 
804
 
 
805
error:
 
806
  // unexpected error
 
807
  if ( errMsg != NULL )
 
808
  {
 
809
    QString error = "maxValue() SQL error: ";
 
810
    error = errMsg;
 
811
    QgsLogger::critical( error );
 
812
    sqlite3_free( errMsg );
 
813
  }
 
814
  return QVariant( QString::null );
 
815
}
 
816
 
 
817
// Returns the list of unique values of an attribute
 
818
void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueValues, int limit )
 
819
{
 
820
  sqlite3_stmt *stmt = NULL;
 
821
  char *errMsg = NULL;
 
822
  QString sql;
 
823
  QString txt;
 
824
 
 
825
  uniqueValues.clear();
 
826
 
 
827
  // get the field name
 
828
  const QgsField & fld = field( index );
 
829
 
 
830
  sql = QString( "SELECT DISTINCT \"%1\" FROM \"%2\" ORDER BY \"%1\"" ).arg( fld.name() ).arg( mTableName );
 
831
 
 
832
  if ( !mSubsetString.isEmpty() )
 
833
  {
 
834
    sql += " WHERE ( " + mSubsetString + ")";
 
835
  }
 
836
 
 
837
  if ( limit >= 0 )
 
838
  {
 
839
    sql += QString( " LIMIT %1" ).arg( limit );
 
840
  }
 
841
 
 
842
  // SQLite prepared statement
 
843
  if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
 
844
  {
 
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 );
 
849
    return;
 
850
  }
 
851
 
 
852
  while ( 1 )
 
853
  {
 
854
    // this one is an infinitive loop, intended to fetch any row
 
855
    int ret = sqlite3_step( stmt );
 
856
 
 
857
    if ( ret == SQLITE_DONE )
 
858
    {
 
859
      // there are no more rows to fetch - we can stop looping
 
860
      break;
 
861
    }
 
862
 
 
863
    if ( ret == SQLITE_ROW )
 
864
    {
 
865
      // fetching one column value
 
866
      switch ( sqlite3_column_type( stmt, 0 ) )
 
867
      {
 
868
        case SQLITE_INTEGER:
 
869
          uniqueValues.append( QString( "%1" ).arg( sqlite3_column_int( stmt, 0 ) ) );
 
870
          break;
 
871
        case SQLITE_FLOAT:
 
872
          uniqueValues.append( QString( "%1" ).arg( sqlite3_column_double( stmt, 0 ) ) );
 
873
          break;
 
874
        case SQLITE_TEXT:
 
875
          uniqueValues.append( QString::fromUtf8(( const char * ) sqlite3_column_text( stmt, 0 ) ) );
 
876
          break;
 
877
        default:
 
878
          uniqueValues.append( "" );
 
879
          break;
 
880
      }
 
881
    }
 
882
    else
 
883
    {
 
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 );
 
889
      goto abort;
 
890
    }
 
891
  }
 
892
  sqlite3_finalize( stmt );
 
893
 
 
894
  return;
 
895
 
 
896
abort:
 
897
  QString msg = QString( "getUniqueValues SQL error:\n%1\n" ).arg( sql );
 
898
  if ( errMsg )
 
899
  {
 
900
    msg += errMsg;
 
901
    sqlite3_free( errMsg );
 
902
  }
 
903
  else
 
904
    msg += "unknown cause";
 
905
  QgsLogger::critical( msg );
 
906
}
 
907
 
 
908
bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist )
 
909
{
 
910
  sqlite3_stmt *stmt = NULL;
 
911
  char *errMsg = NULL;
 
912
  bool toCommit = false;
 
913
  QString sql;
 
914
  QString values;
 
915
  int ia;
 
916
 
 
917
  if ( flist.size() == 0 )
 
918
    return true;
 
919
  const QgsAttributeMap & attributevec = flist[0].attributeMap();
 
920
 
 
921
  int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
 
922
  if ( ret != SQLITE_OK )
 
923
  {
 
924
    // some error occurred
 
925
    goto abort;
 
926
  }
 
927
  toCommit = true;
 
928
 
 
929
  if ( !mPrimaryKey.isEmpty() )
 
930
  {
 
931
    sql = QString( "INSERT INTO \"%1\" (\"%2\", \"%3\"" ).
 
932
          arg( mTableName ).arg( mPrimaryKey ).arg( mGeometryColumn );
 
933
    values = QString( ") VALUES (NULL, GeomFromWKB(?, %1)" ).arg( mSrid );
 
934
  }
 
935
  else
 
936
  {
 
937
    sql = QString( "INSERT INTO \"%1\" (\"%2\"" ).arg( mTableName ).arg( mGeometryColumn );
 
938
    values = QString( ") VALUES (GeomFromWKB(?, %1)" ).arg( mSrid );
 
939
  }
 
940
 
 
941
  for ( QgsAttributeMap::const_iterator it = attributevec.begin(); it != attributevec.end(); it++ )
 
942
  {
 
943
    QgsFieldMap::const_iterator fit = attributeFields.find( it.key() );
 
944
    if ( fit == attributeFields.end() )
 
945
      continue;
 
946
 
 
947
    QString fieldname = fit->name();
 
948
    if ( fieldname.isEmpty() || fieldname == mGeometryColumn || fieldname == mPrimaryKey )
 
949
      continue;
 
950
 
 
951
    sql += ", \"";
 
952
    sql += fieldname;
 
953
    sql += "\"";
 
954
    values += ", ?";
 
955
  }
 
956
 
 
957
  sql += values;
 
958
  sql += ")";
 
959
 
 
960
  // SQLite prepared statement
 
961
  if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
 
962
  {
 
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 );
 
967
    return false;
 
968
  }
 
969
 
 
970
  for ( QgsFeatureList::iterator features = flist.begin(); features != flist.end(); features++ )
 
971
  {
 
972
    // looping on each feature to insert
 
973
    const QgsAttributeMap & attributevec = features->attributeMap();
 
974
 
 
975
    // resetting Prepared Statement and bindings
 
976
    sqlite3_reset( stmt );
 
977
    sqlite3_clear_bindings( stmt );
 
978
 
 
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 );
 
982
 
 
983
    // initializing the column counter
 
984
    ia = 1;
 
985
 
 
986
    for ( QgsAttributeMap::const_iterator it = attributevec.begin(); it != attributevec.end(); it++ )
 
987
    {
 
988
      // binding values for each attribute
 
989
      QgsFieldMap::const_iterator fit = attributeFields.find( it.key() );
 
990
      if ( fit == attributeFields.end() )
 
991
        continue;
 
992
 
 
993
      QString fieldname = fit->name();
 
994
      if ( fieldname.isEmpty() || fieldname == mGeometryColumn || fieldname == mPrimaryKey )
 
995
        continue;
 
996
 
 
997
      QVariant::Type type = fit->type();
 
998
      if ( it->toString().isEmpty() )
 
999
      {
 
1000
        // assuming to be a NULL value
 
1001
        type = QVariant::Invalid;
 
1002
      }
 
1003
 
 
1004
      if ( type == QVariant::Int )
 
1005
      {
 
1006
        // binding an INTEGER value
 
1007
        sqlite3_bind_int( stmt, ++ia, it->toInt() );
 
1008
      }
 
1009
      else if ( type == QVariant::Double )
 
1010
      {
 
1011
        // binding a DOUBLE value
 
1012
        sqlite3_bind_double( stmt, ++ia, it->toDouble() );
 
1013
      }
 
1014
      else if ( type == QVariant::String )
 
1015
      {
 
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 );
 
1022
        delete [] vl;
 
1023
      }
 
1024
      else
 
1025
      {
 
1026
        // binding a NULL value
 
1027
        sqlite3_bind_null( stmt, ++ia );
 
1028
      }
 
1029
    }
 
1030
 
 
1031
    // performing actual row insert
 
1032
    ret = sqlite3_step( stmt );
 
1033
 
 
1034
    if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
 
1035
    {
 
1036
      numberFeatures++;
 
1037
    }
 
1038
    else
 
1039
    {
 
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 );
 
1045
      goto abort;
 
1046
    }
 
1047
 
 
1048
  }
 
1049
  sqlite3_finalize( stmt );
 
1050
 
 
1051
  ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
 
1052
  if ( ret != SQLITE_OK )
 
1053
  {
 
1054
    // some error occurred
 
1055
    goto abort;
 
1056
  }
 
1057
  return true;
 
1058
 
 
1059
abort:
 
1060
  QString msg = QString( "addFeatures SQL error:\n%1\n" ).arg( sql );
 
1061
  if ( errMsg )
 
1062
  {
 
1063
    msg += errMsg;
 
1064
    sqlite3_free( errMsg );
 
1065
  }
 
1066
  else
 
1067
    msg += "unknown cause";
 
1068
  QgsLogger::critical( msg );
 
1069
 
 
1070
  if ( toCommit )
 
1071
  {
 
1072
    // ROLLBACK after some previous error
 
1073
    sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
 
1074
  }
 
1075
 
 
1076
  return false;
 
1077
}
 
1078
 
 
1079
bool QgsSpatiaLiteProvider::deleteFeatures( const QgsFeatureIds & id )
 
1080
{
 
1081
  sqlite3_stmt *stmt = NULL;
 
1082
  char *errMsg = NULL;
 
1083
  bool toCommit = false;
 
1084
  QString sql;
 
1085
 
 
1086
  int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
 
1087
  if ( ret != SQLITE_OK )
 
1088
  {
 
1089
    // some error occurred
 
1090
    goto abort;
 
1091
  }
 
1092
  toCommit = true;
 
1093
 
 
1094
  sql = QString( "DELETE FROM \"%1\" WHERE ROWID = ?" ).arg( mTableName );
 
1095
 
 
1096
  // SQLite prepared statement
 
1097
  if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
 
1098
  {
 
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 );
 
1103
    return false;
 
1104
  }
 
1105
 
 
1106
  for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
 
1107
  {
 
1108
    // looping on each feature to be deleted
 
1109
    // resetting Prepared Statement and bindings
 
1110
    sqlite3_reset( stmt );
 
1111
    sqlite3_clear_bindings( stmt );
 
1112
 
 
1113
    sqlite3_bind_int( stmt, 1, *it );
 
1114
 
 
1115
    // performing actual row deletion
 
1116
    ret = sqlite3_step( stmt );
 
1117
    if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
 
1118
    {
 
1119
      numberFeatures--;
 
1120
    }
 
1121
    else
 
1122
    {
 
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 );
 
1128
      goto abort;
 
1129
    }
 
1130
  }
 
1131
  sqlite3_finalize( stmt );
 
1132
 
 
1133
  ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
 
1134
  if ( ret != SQLITE_OK )
 
1135
  {
 
1136
    // some error occurred
 
1137
    goto abort;
 
1138
  }
 
1139
 
 
1140
  return true;
 
1141
 
 
1142
abort:
 
1143
  QString msg = QString( "deleteFeatures SQL error:\n%1\n" ).arg( sql );
 
1144
  if ( errMsg )
 
1145
  {
 
1146
    msg += errMsg;
 
1147
    sqlite3_free( errMsg );
 
1148
  }
 
1149
  else
 
1150
    msg += "unknown cause";
 
1151
  QgsLogger::critical( msg );
 
1152
 
 
1153
  if ( toCommit )
 
1154
  {
 
1155
    // ROLLBACK after some previous error
 
1156
    sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
 
1157
  }
 
1158
 
 
1159
  return false;
 
1160
}
 
1161
 
 
1162
bool QgsSpatiaLiteProvider::addAttributes( const QList<QgsField> &attributes )
 
1163
{
 
1164
  char *errMsg = NULL;
 
1165
  bool toCommit = false;
 
1166
  QString sql;
 
1167
 
 
1168
  int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
 
1169
  if ( ret != SQLITE_OK )
 
1170
  {
 
1171
    // some error occurred
 
1172
    goto abort;
 
1173
  }
 
1174
  toCommit = true;
 
1175
 
 
1176
  for ( QList<QgsField>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter )
 
1177
  {
 
1178
    sql = QString( "ALTER TABLE \"%1\" ADD COLUMN \"%2\" %3" )
 
1179
          .arg( mTableName )
 
1180
          .arg( iter->name() )
 
1181
          .arg( iter->typeName() );
 
1182
    ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), NULL, NULL, &errMsg );
 
1183
    if ( ret != SQLITE_OK )
 
1184
    {
 
1185
      // some error occurred
 
1186
      goto abort;
 
1187
    }
 
1188
  }
 
1189
 
 
1190
  ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
 
1191
  if ( ret != SQLITE_OK )
 
1192
  {
 
1193
    // some error occurred
 
1194
    goto abort;
 
1195
  }
 
1196
 
 
1197
  return true;
 
1198
 
 
1199
abort:
 
1200
  QString msg = QString( "addAttributes SQL error:\n%1\n" ).arg( sql );
 
1201
  if ( errMsg )
 
1202
  {
 
1203
    msg += errMsg;
 
1204
    sqlite3_free( errMsg );
 
1205
  }
 
1206
  else
 
1207
    msg += "unknown cause";
 
1208
  QgsLogger::critical( msg );
 
1209
 
 
1210
  if ( toCommit )
 
1211
  {
 
1212
    // ROLLBACK after some previous error
 
1213
    sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
 
1214
  }
 
1215
 
 
1216
  return false;
 
1217
}
 
1218
 
 
1219
bool QgsSpatiaLiteProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
 
1220
{
 
1221
  char *errMsg = NULL;
 
1222
  bool toCommit = false;
 
1223
  QString sql;
 
1224
 
 
1225
  int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
 
1226
  if ( ret != SQLITE_OK )
 
1227
  {
 
1228
    // some error occurred
 
1229
    goto abort;
 
1230
  }
 
1231
  toCommit = true;
 
1232
 
 
1233
  for ( QgsChangedAttributesMap::const_iterator iter = attr_map.begin(); iter != attr_map.end(); ++iter )
 
1234
  {
 
1235
    int fid = iter.key();
 
1236
 
 
1237
    // skip added features
 
1238
    if ( fid < 0 )
 
1239
      continue;
 
1240
 
 
1241
    QString sql = QString( "UPDATE \"%1\" SET " ).arg( mTableName );
 
1242
    bool first = true;
 
1243
 
 
1244
    const QgsAttributeMap & attrs = iter.value();
 
1245
 
 
1246
    // cycle through the changed attributes of the feature
 
1247
    for ( QgsAttributeMap::const_iterator siter = attrs.begin(); siter != attrs.end(); ++siter )
 
1248
    {
 
1249
      QString fieldName = field( siter.key() ).name();
 
1250
 
 
1251
      if ( !first )
 
1252
        sql += ",";
 
1253
      else
 
1254
        first = false;
 
1255
 
 
1256
      QVariant::Type type = siter->type();
 
1257
      if ( siter->toString().isEmpty() )
 
1258
      {
 
1259
        // assuming to be a NULL value
 
1260
        type = QVariant::Invalid;
 
1261
      }
 
1262
 
 
1263
      if ( type == QVariant::Invalid )
 
1264
      {
 
1265
        // binding a NULL value
 
1266
        sql += QString( "\"%1\"=NULL" ).arg( fieldName );
 
1267
      }
 
1268
      else if ( type == QVariant::Int || type == QVariant::Double )
 
1269
      {
 
1270
        // binding a NUMERIC value
 
1271
        sql += QString( "\"%1\"=%2" ).arg( fieldName ).arg( siter->toString() );
 
1272
      }
 
1273
      else
 
1274
      {
 
1275
        // binding a TEXT value
 
1276
        sql += QString( "\"%1\"=%2" ).arg( fieldName ).arg( quotedValue( siter->toString() ) );
 
1277
      }
 
1278
    }
 
1279
    sql += QString( " WHERE ROWID=%1" ).arg( fid );
 
1280
 
 
1281
    ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), NULL, NULL, &errMsg );
 
1282
    if ( ret != SQLITE_OK )
 
1283
    {
 
1284
      // some error occurred
 
1285
      goto abort;
 
1286
    }
 
1287
  }
 
1288
 
 
1289
  ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
 
1290
  if ( ret != SQLITE_OK )
 
1291
  {
 
1292
    // some error occurred
 
1293
    goto abort;
 
1294
  }
 
1295
 
 
1296
  return true;
 
1297
 
 
1298
abort:
 
1299
  QString msg = QString( "changeAttributeValues SQL error:\n%1\n" ).arg( sql );
 
1300
  if ( errMsg )
 
1301
  {
 
1302
    msg += errMsg;
 
1303
    sqlite3_free( errMsg );
 
1304
  }
 
1305
  else
 
1306
    msg += "unknown cause";
 
1307
  QgsLogger::critical( msg );
 
1308
 
 
1309
  if ( toCommit )
 
1310
  {
 
1311
    // ROLLBACK after some previous error
 
1312
    sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
 
1313
  }
 
1314
 
 
1315
  return false;
 
1316
}
 
1317
 
 
1318
bool QgsSpatiaLiteProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
 
1319
{
 
1320
  sqlite3_stmt *stmt = NULL;
 
1321
  char *errMsg = NULL;
 
1322
  bool toCommit = false;
 
1323
  QString sql;
 
1324
 
 
1325
  int ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
 
1326
  if ( ret != SQLITE_OK )
 
1327
  {
 
1328
    // some error occurred
 
1329
    goto abort;
 
1330
  }
 
1331
  toCommit = true;
 
1332
 
 
1333
  sql =
 
1334
    QString( "UPDATE \"%1\" SET \"%2\" = GeomFromWKB(?, %3) WHERE ROWID = ?" ).
 
1335
    arg( mTableName ).arg( mGeometryColumn ).arg( mSrid );
 
1336
 
 
1337
  // SQLite prepared statement
 
1338
  if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
 
1339
  {
 
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 );
 
1344
    return false;
 
1345
  }
 
1346
 
 
1347
  for ( QgsGeometryMap::iterator iter = geometry_map.begin(); iter != geometry_map.end(); ++iter )
 
1348
  {
 
1349
    // looping on each feature to change
 
1350
    if ( iter->asWkb() )
 
1351
    {
 
1352
 
 
1353
      // resetting Prepared Statement and bindings
 
1354
      sqlite3_reset( stmt );
 
1355
      sqlite3_clear_bindings( stmt );
 
1356
 
 
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() );
 
1361
 
 
1362
      // performing actual row update
 
1363
      ret = sqlite3_step( stmt );
 
1364
      if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
 
1365
        ;
 
1366
      else
 
1367
      {
 
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 );
 
1373
        goto abort;
 
1374
      }
 
1375
 
 
1376
    }
 
1377
  }
 
1378
  sqlite3_finalize( stmt );
 
1379
 
 
1380
  ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
 
1381
  if ( ret != SQLITE_OK )
 
1382
  {
 
1383
    // some error occurred
 
1384
    goto abort;
 
1385
  }
 
1386
  return true;
 
1387
 
 
1388
abort:
 
1389
  QString msg = QString( "addFeatures SQL error:\n%1\n" ).arg( sql );
 
1390
  if ( errMsg )
 
1391
  {
 
1392
    msg += errMsg;
 
1393
    sqlite3_free( errMsg );
 
1394
  }
 
1395
  else
 
1396
    msg += "unknown cause";
 
1397
  QgsLogger::critical( msg );
 
1398
 
 
1399
  if ( toCommit )
 
1400
  {
 
1401
    // ROLLBACK after some previous error
 
1402
    sqlite3_exec( sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
 
1403
  }
 
1404
 
 
1405
  return false;
 
1406
}
 
1407
 
 
1408
 
 
1409
int QgsSpatiaLiteProvider::capabilities() const
 
1410
{
 
1411
  return enabledCapabilities;
 
1412
}
 
1413
 
 
1414
void QgsSpatiaLiteProvider::closeDb()
 
1415
{
 
1416
// trying to close the SQLite DB
 
1417
  if ( sqliteStatement )
 
1418
  {
 
1419
    sqlite3_finalize( sqliteStatement );
 
1420
    sqliteStatement = NULL;
 
1421
  }
 
1422
  if ( handle )
 
1423
  {
 
1424
    SqliteHandles::closeDb( handle );
 
1425
  }
 
1426
}
 
1427
 
 
1428
bool QgsSpatiaLiteProvider::SqliteHandles::checkMetadata( sqlite3 *handle )
 
1429
{
 
1430
  int ret;
 
1431
  int i;
 
1432
  char **results;
 
1433
  int rows;
 
1434
  int columns;
 
1435
  int spatial_type = 0;
 
1436
  ret = sqlite3_get_table( handle, "SELECT CheckSpatialMetadata()", &results, &rows, &columns, NULL );
 
1437
  if ( ret != SQLITE_OK )
 
1438
    goto skip;
 
1439
  if ( rows < 1 )
 
1440
    ;
 
1441
  else
 
1442
  {
 
1443
    for ( i = 1; i <= rows; i++ )
 
1444
      spatial_type = atoi( results[( i * columns ) + 0] );
 
1445
  }
 
1446
  sqlite3_free_table( results );
 
1447
skip:
 
1448
  if ( spatial_type == 1 )
 
1449
    return true;
 
1450
  return false;
 
1451
}
 
1452
 
 
1453
QgsSpatiaLiteProvider::SqliteHandles * QgsSpatiaLiteProvider::SqliteHandles::openDb( const QString & dbPath )
 
1454
{
 
1455
  sqlite3 *sqlite_handle;
 
1456
 
 
1457
  QMap < QString, QgsSpatiaLiteProvider::SqliteHandles * >&handles = QgsSpatiaLiteProvider::SqliteHandles::handles;
 
1458
 
 
1459
  if ( handles.contains( dbPath ) )
 
1460
  {
 
1461
    QgsDebugMsg( QString( "Using cached connection for %1" ).arg( dbPath ) );
 
1462
    handles[dbPath]->ref++;
 
1463
    return handles[dbPath];
 
1464
  }
 
1465
 
 
1466
  QgsDebugMsg( QString( "New sqlite connection for " ) + dbPath );
 
1467
  if ( sqlite3_open_v2( dbPath.toUtf8().constData(), &sqlite_handle, SQLITE_OPEN_READWRITE, NULL ) )
 
1468
  {
 
1469
    // failure
 
1470
 
 
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 );
 
1474
    return NULL;
 
1475
  }
 
1476
 
 
1477
  // checking the DB for sanity
 
1478
  if ( checkMetadata( sqlite_handle ) == false )
 
1479
  {
 
1480
    // failure
 
1481
 
 
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 );
 
1486
    return NULL;
 
1487
  }
 
1488
  // activating Foreign Key constraints
 
1489
  sqlite3_exec( sqlite_handle, "PRAGMA foreign_keys = 1", NULL, 0, NULL );
 
1490
 
 
1491
  QgsDebugMsg( "Connection to the database was successful" );
 
1492
 
 
1493
  SqliteHandles *handle = new SqliteHandles( sqlite_handle );
 
1494
  handles.insert( dbPath, handle );
 
1495
 
 
1496
  return handle;
 
1497
}
 
1498
 
 
1499
void QgsSpatiaLiteProvider::SqliteHandles::closeDb( SqliteHandles * &handle )
 
1500
{
 
1501
  closeDb( handles, handle );
 
1502
}
 
1503
 
 
1504
void QgsSpatiaLiteProvider::SqliteHandles::closeDb( QMap < QString, SqliteHandles * >&handles, SqliteHandles * &handle )
 
1505
{
 
1506
  QMap < QString, SqliteHandles * >::iterator i;
 
1507
  for ( i = handles.begin(); i != handles.end() && i.value() != handle; i++ )
 
1508
    ;
 
1509
 
 
1510
  assert( i.value() == handle );
 
1511
  assert( i.value()->ref > 0 );
 
1512
 
 
1513
  if ( --i.value()->ref == 0 )
 
1514
  {
 
1515
    i.value()->sqliteClose();
 
1516
    delete i.value();
 
1517
    handles.remove( i.key() );
 
1518
  }
 
1519
 
 
1520
  handle = NULL;
 
1521
}
 
1522
 
 
1523
void QgsSpatiaLiteProvider::SqliteHandles::sqliteClose()
 
1524
{
 
1525
  if ( sqlite_handle )
 
1526
  {
 
1527
    sqlite3_close( sqlite_handle );
 
1528
    sqlite_handle = NULL;
 
1529
  }
 
1530
}
 
1531
 
 
1532
QString QgsSpatiaLiteProvider::quotedValue( QString value ) const
 
1533
{
 
1534
  if ( value.isNull() )
 
1535
    return "NULL";
 
1536
 
 
1537
  value.replace( "'", "''" );
 
1538
  return value.prepend( "'" ).append( "'" );
 
1539
}
 
1540
 
 
1541
bool QgsSpatiaLiteProvider::checkLayerType()
 
1542
{
 
1543
  int ret;
 
1544
  int i;
 
1545
  char **results;
 
1546
  int rows;
 
1547
  int columns;
 
1548
  char *errMsg = NULL;
 
1549
  int count = 0;
 
1550
 
 
1551
  mTableBased = false;
 
1552
  mViewBased = false;
 
1553
  mVShapeBased = false;
 
1554
 
 
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 ) );
 
1561
 
 
1562
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
1563
  if ( ret != SQLITE_OK )
 
1564
    goto error;
 
1565
  if ( rows < 1 )
 
1566
    ;
 
1567
  else
 
1568
  {
 
1569
    mTableBased = true;
 
1570
    mReadOnly = false;
 
1571
    for ( i = 1; i <= rows; i++ )
 
1572
    {
 
1573
      if ( results[( i * columns ) + 0] != NULL )
 
1574
      {
 
1575
        if ( atoi( results[( i * columns ) + 0] ) != 0 )
 
1576
          mReadOnly = true;
 
1577
      }
 
1578
    }
 
1579
    count++;
 
1580
  }
 
1581
  sqlite3_free_table( results );
 
1582
 
 
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 ) );
 
1587
 
 
1588
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
1589
  if ( ret != SQLITE_OK )
 
1590
    goto error;
 
1591
  if ( rows < 1 )
 
1592
    ;
 
1593
  else
 
1594
  {
 
1595
    mViewBased = true;
 
1596
    mReadOnly = true;
 
1597
    count++;
 
1598
  }
 
1599
  sqlite3_free_table( results );
 
1600
 
 
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 ) );
 
1605
 
 
1606
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
1607
  if ( ret != SQLITE_OK )
 
1608
    goto error;
 
1609
  if ( rows < 1 )
 
1610
    ;
 
1611
  else
 
1612
  {
 
1613
    mVShapeBased = true;
 
1614
    mReadOnly = true;
 
1615
    count++;
 
1616
  }
 
1617
  sqlite3_free_table( results );
 
1618
 
 
1619
// cheching for validity
 
1620
  if ( count != 1 )
 
1621
    return false;
 
1622
 
 
1623
  return true;
 
1624
 
 
1625
error:
 
1626
  // unexpected error
 
1627
  if ( errMsg != NULL )
 
1628
  {
 
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 );
 
1633
  }
 
1634
  return false;
 
1635
}
 
1636
 
 
1637
bool QgsSpatiaLiteProvider::getGeometryDetails()
 
1638
{
 
1639
  bool ret = false;
 
1640
  if ( mTableBased )
 
1641
    ret = getTableGeometryDetails();
 
1642
  if ( mViewBased )
 
1643
    ret = getViewGeometryDetails();
 
1644
  if ( mVShapeBased )
 
1645
    ret = getVShapeGeometryDetails();
 
1646
  return ret;
 
1647
}
 
1648
 
 
1649
bool QgsSpatiaLiteProvider::getTableGeometryDetails()
 
1650
{
 
1651
  int ret;
 
1652
  int i;
 
1653
  char **results;
 
1654
  int rows;
 
1655
  int columns;
 
1656
  char *errMsg = NULL;
 
1657
 
 
1658
  mIndexTable = mTableName;
 
1659
  mIndexGeometry = mGeometryColumn;
 
1660
 
 
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 ) );
 
1664
 
 
1665
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
1666
  if ( ret != SQLITE_OK )
 
1667
    goto error;
 
1668
  if ( rows < 1 )
 
1669
    ;
 
1670
  else
 
1671
  {
 
1672
    for ( i = 1; i <= rows; i++ )
 
1673
    {
 
1674
      QString fType = results[( i * columns ) + 0];
 
1675
      QString xSrid = results[( i * columns ) + 1];
 
1676
      QString spatialIndex = results[( i * columns ) + 2];
 
1677
 
 
1678
      if ( fType == "POINT" )
 
1679
      {
 
1680
        geomType = QGis::WKBPoint;
 
1681
      }
 
1682
      else if ( fType == "MULTIPOINT" )
 
1683
      {
 
1684
        geomType = QGis::WKBMultiPoint;
 
1685
      }
 
1686
      else if ( fType == "LINESTRING" )
 
1687
      {
 
1688
        geomType = QGis::WKBLineString;
 
1689
      }
 
1690
      else if ( fType == "MULTILINESTRING" )
 
1691
      {
 
1692
        geomType = QGis::WKBMultiLineString;
 
1693
      }
 
1694
      else if ( fType == "POLYGON" )
 
1695
      {
 
1696
        geomType = QGis::WKBPolygon;
 
1697
      }
 
1698
      else if ( fType == "MULTIPOLYGON" )
 
1699
      {
 
1700
        geomType = QGis::WKBMultiPolygon;
 
1701
      }
 
1702
      mSrid = xSrid.toInt();
 
1703
      if ( spatialIndex.toInt() == 1 )
 
1704
      {
 
1705
        spatialIndexRTree = true;
 
1706
      }
 
1707
      if ( spatialIndex.toInt() == 2 )
 
1708
      {
 
1709
        spatialIndexMbrCache = true;
 
1710
      }
 
1711
 
 
1712
    }
 
1713
  }
 
1714
  sqlite3_free_table( results );
 
1715
 
 
1716
  if ( geomType == QGis::WKBUnknown || mSrid < 0 )
 
1717
    goto error;
 
1718
 
 
1719
  return getSridDetails();
 
1720
 
 
1721
error:
 
1722
  // unexpected error
 
1723
  if ( errMsg != NULL )
 
1724
  {
 
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 );
 
1729
  }
 
1730
  return false;
 
1731
}
 
1732
 
 
1733
bool QgsSpatiaLiteProvider::getViewGeometryDetails()
 
1734
{
 
1735
  int ret;
 
1736
  int i;
 
1737
  char **results;
 
1738
  int rows;
 
1739
  int columns;
 
1740
  char *errMsg = NULL;
 
1741
 
 
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 ) );
 
1747
 
 
1748
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
1749
  if ( ret != SQLITE_OK )
 
1750
    goto error;
 
1751
  if ( rows < 1 )
 
1752
    ;
 
1753
  else
 
1754
  {
 
1755
    for ( i = 1; i <= rows; i++ )
 
1756
    {
 
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];
 
1762
 
 
1763
      if ( fType == "POINT" )
 
1764
      {
 
1765
        geomType = QGis::WKBPoint;
 
1766
      }
 
1767
      else if ( fType == "MULTIPOINT" )
 
1768
      {
 
1769
        geomType = QGis::WKBMultiPoint;
 
1770
      }
 
1771
      else if ( fType == "LINESTRING" )
 
1772
      {
 
1773
        geomType = QGis::WKBLineString;
 
1774
      }
 
1775
      else if ( fType == "MULTILINESTRING" )
 
1776
      {
 
1777
        geomType = QGis::WKBMultiLineString;
 
1778
      }
 
1779
      else if ( fType == "POLYGON" )
 
1780
      {
 
1781
        geomType = QGis::WKBPolygon;
 
1782
      }
 
1783
      else if ( fType == "MULTIPOLYGON" )
 
1784
      {
 
1785
        geomType = QGis::WKBMultiPolygon;
 
1786
      }
 
1787
      mSrid = xSrid.toInt();
 
1788
      if ( spatialIndex.toInt() == 1 )
 
1789
      {
 
1790
        spatialIndexRTree = true;
 
1791
      }
 
1792
      if ( spatialIndex.toInt() == 2 )
 
1793
      {
 
1794
        spatialIndexMbrCache = true;
 
1795
      }
 
1796
 
 
1797
    }
 
1798
  }
 
1799
  sqlite3_free_table( results );
 
1800
 
 
1801
  if ( geomType == QGis::WKBUnknown || mSrid < 0 )
 
1802
    goto error;
 
1803
 
 
1804
  return getSridDetails();
 
1805
 
 
1806
error:
 
1807
  // unexpected error
 
1808
  if ( errMsg != NULL )
 
1809
  {
 
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 );
 
1814
  }
 
1815
  return false;
 
1816
}
 
1817
 
 
1818
bool QgsSpatiaLiteProvider::getVShapeGeometryDetails()
 
1819
{
 
1820
  int ret;
 
1821
  int i;
 
1822
  char **results;
 
1823
  int rows;
 
1824
  int columns;
 
1825
  char *errMsg = NULL;
 
1826
 
 
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 ) );
 
1830
 
 
1831
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
1832
  if ( ret != SQLITE_OK )
 
1833
    goto error;
 
1834
  if ( rows < 1 )
 
1835
    ;
 
1836
  else
 
1837
  {
 
1838
    for ( i = 1; i <= rows; i++ )
 
1839
    {
 
1840
      QString fType = results[( i * columns ) + 0];
 
1841
      QString xSrid = results[( i * columns ) + 1];
 
1842
 
 
1843
      if ( fType == "POINT" )
 
1844
      {
 
1845
        geomType = QGis::WKBPoint;
 
1846
      }
 
1847
      else if ( fType == "MULTIPOINT" )
 
1848
      {
 
1849
        geomType = QGis::WKBMultiPoint;
 
1850
      }
 
1851
      else if ( fType == "LINESTRING" )
 
1852
      {
 
1853
        geomType = QGis::WKBLineString;
 
1854
      }
 
1855
      else if ( fType == "MULTILINESTRING" )
 
1856
      {
 
1857
        geomType = QGis::WKBMultiLineString;
 
1858
      }
 
1859
      else if ( fType == "POLYGON" )
 
1860
      {
 
1861
        geomType = QGis::WKBPolygon;
 
1862
      }
 
1863
      else if ( fType == "MULTIPOLYGON" )
 
1864
      {
 
1865
        geomType = QGis::WKBMultiPolygon;
 
1866
      }
 
1867
      mSrid = xSrid.toInt();
 
1868
 
 
1869
    }
 
1870
  }
 
1871
  sqlite3_free_table( results );
 
1872
 
 
1873
  if ( geomType == QGis::WKBUnknown || mSrid < 0 )
 
1874
    goto error;
 
1875
 
 
1876
  return getSridDetails();
 
1877
 
 
1878
error:
 
1879
  // unexpected error
 
1880
  if ( errMsg != NULL )
 
1881
  {
 
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 );
 
1886
  }
 
1887
  return false;
 
1888
}
 
1889
 
 
1890
bool QgsSpatiaLiteProvider::getSridDetails()
 
1891
{
 
1892
  int ret;
 
1893
  int i;
 
1894
  char **results;
 
1895
  int rows;
 
1896
  int columns;
 
1897
  char *errMsg = NULL;
 
1898
 
 
1899
  QString sql = QString( "SELECT proj4text FROM spatial_ref_sys WHERE srid=%1" ).arg( mSrid );
 
1900
 
 
1901
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
1902
  if ( ret != SQLITE_OK )
 
1903
    goto error;
 
1904
  if ( rows < 1 )
 
1905
    ;
 
1906
  else
 
1907
  {
 
1908
    for ( i = 1; i <= rows; i++ )
 
1909
    {
 
1910
      mProj4text = results[( i * columns ) + 0];
 
1911
    }
 
1912
  }
 
1913
  sqlite3_free_table( results );
 
1914
 
 
1915
  return true;
 
1916
 
 
1917
error:
 
1918
  // unexpected error
 
1919
  if ( errMsg != NULL )
 
1920
  {
 
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 );
 
1925
  }
 
1926
  return false;
 
1927
}
 
1928
 
 
1929
bool QgsSpatiaLiteProvider::getTableSummary()
 
1930
{
 
1931
  int ret;
 
1932
  int i;
 
1933
  char **results;
 
1934
  int rows;
 
1935
  int columns;
 
1936
  char *errMsg = NULL;
 
1937
 
 
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 );
 
1940
 
 
1941
  if ( !mSubsetString.isEmpty() )
 
1942
  {
 
1943
    sql += " WHERE ( " + mSubsetString + ")";
 
1944
  }
 
1945
 
 
1946
  ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
 
1947
  if ( ret != SQLITE_OK )
 
1948
    goto error;
 
1949
  if ( rows < 1 )
 
1950
    ;
 
1951
  else
 
1952
  {
 
1953
    for ( i = 1; i <= rows; i++ )
 
1954
    {
 
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];
 
1960
 
 
1961
      layerExtent.set( minX.toDouble(), minY.toDouble(), maxX.toDouble(), maxY.toDouble() );
 
1962
      numberFeatures = count.toLong();
 
1963
    }
 
1964
  }
 
1965
  sqlite3_free_table( results );
 
1966
  return true;
 
1967
 
 
1968
error:
 
1969
  // unexpected error
 
1970
  if ( errMsg != NULL )
 
1971
  {
 
1972
    QString error = "getTableSummary() SQL error: ";
 
1973
    error = errMsg;
 
1974
    QgsLogger::critical( error );
 
1975
    sqlite3_free( errMsg );
 
1976
  }
 
1977
  return false;
 
1978
}
 
1979
 
 
1980
const QgsField & QgsSpatiaLiteProvider::field( int index ) const
 
1981
{
 
1982
  QgsFieldMap::const_iterator it = attributeFields.find( index );
 
1983
 
 
1984
  if ( it == attributeFields.constEnd() )
 
1985
  {
 
1986
    QgsLogger::critical( "Field " + QString::number( index ) + " not found." );
 
1987
  }
 
1988
 
 
1989
  return it.value();
 
1990
}
 
1991
 
 
1992
 
 
1993
 
 
1994
/**
 
1995
 * Class factory to return a pointer to a newly created
 
1996
 * QgsSpatiaLiteProvider object
 
1997
 */
 
1998
QGISEXTERN QgsSpatiaLiteProvider *classFactory( const QString * uri )
 
1999
{
 
2000
  return new QgsSpatiaLiteProvider( *uri );
 
2001
}
 
2002
 
 
2003
/** Required key function (used to map the plugin to a data store type)
 
2004
*/
 
2005
QGISEXTERN QString providerKey()
 
2006
{
 
2007
  return SPATIALITE_KEY;
 
2008
}
 
2009
 
 
2010
/**
 
2011
 * Required description function
 
2012
 */
 
2013
QGISEXTERN QString description()
 
2014
{
 
2015
  return SPATIALITE_DESCRIPTION;
 
2016
}
 
2017
 
 
2018
/**
 
2019
 * Required isProvider function. Used to determine if this shared library
 
2020
 * is a data provider plugin
 
2021
 */
 
2022
QGISEXTERN bool isProvider()
 
2023
{
 
2024
  return true;
 
2025
}