Statistics
| Branch: | Tag: | Revision:

qgis / src / providers / ogr / qgsogrprovider.h @ master

History | View | Annotate | Download (18.7 KB)

1
/***************************************************************************
2
            qgsogrprovider.h Data provider for ESRI shapefile format
3
                    Formerly known as qgsshapefileprovider.h
4
begin                : Oct 29, 2003
5
copyright            : (C) 2003 by Gary E.Sherman
6
email                : sherman at mrcc.com
7
 ***************************************************************************/
8

    
9
/***************************************************************************
10
 *                                                                         *
11
 *   This program is free software; you can redistribute it and/or modify  *
12
 *   it under the terms of the GNU General Public License as published by  *
13
 *   the Free Software Foundation; either version 2 of the License, or     *
14
 *   (at your option) any later version.                                   *
15
 *                                                                         *
16
 ***************************************************************************/
17

    
18
#ifndef QGSOGRPROVIDER_H
19
#define QGSOGRPROVIDER_H
20

    
21
#include "QTextCodec"
22

    
23
#include "qgsrectangle.h"
24
#include "qgsvectordataprovider.h"
25
#include "qgsvectorfilewriter.h"
26
#include "qgsvectorlayerexporter.h"
27

    
28
class QgsField;
29
class QgsVectorLayerExporter;
30

    
31
class QgsOgrFeatureIterator;
32

    
33
#include <gdal.h>
34

    
35
class QgsOgrLayer;
36

    
37
/**
38
  \class QgsOgrProvider
39
  \brief Data provider for OGR datasources
40
  */
41
class QgsOgrProvider : public QgsVectorDataProvider
42
{
43
    Q_OBJECT
44

    
45
  public:
46

    
47
    //! Convert a vector layer to a vector file
48
    static QgsVectorLayerExporter::ExportError createEmptyLayer(
49
      const QString &uri,
50
      const QgsFields &fields,
51
      QgsWkbTypes::Type wkbType,
52
      const QgsCoordinateReferenceSystem &srs,
53
      bool overwrite,
54
      QMap<int, int> *oldToNewAttrIdxMap,
55
      QString *errorMessage = nullptr,
56
      const QMap<QString, QVariant> *options = nullptr
57
    );
58

    
59
    /**
60
     * Constructor of the vector provider
61
     * \param uri  uniform resource locator (URI) for a dataset
62
     */
63
    explicit QgsOgrProvider( QString const &uri = QString() );
64

    
65
    virtual ~QgsOgrProvider();
66

    
67
    virtual QgsAbstractFeatureSource *featureSource() const override;
68

    
69
    virtual QgsCoordinateReferenceSystem crs() const override;
70
    virtual QStringList subLayers() const override;
71
    virtual QString storageType() const override;
72
    virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest &request ) const override;
73
    virtual QString subsetString() const override;
74
    virtual bool supportsSubsetString() const override { return true; }
75
    virtual bool setSubsetString( const QString &theSQL, bool updateFeatureCount = true ) override;
76
    virtual QgsWkbTypes::Type wkbType() const override;
77
    virtual size_t layerCount() const;
78
    virtual long featureCount() const override;
79
    virtual QgsFields fields() const override;
80
    virtual QgsRectangle extent() const override;
81
    QVariant defaultValue( int fieldId ) const override;
82
    virtual void updateExtents() override;
83
    virtual bool addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flags flags = 0 ) override;
84
    virtual bool deleteFeatures( const QgsFeatureIds &id ) override;
85
    virtual bool addAttributes( const QList<QgsField> &attributes ) override;
86
    virtual bool deleteAttributes( const QgsAttributeIds &attributes ) override;
87
    virtual bool renameAttributes( const QgsFieldNameMap &renamedAttributes ) override;
88
    virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;
89
    virtual bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;
90
    virtual bool createSpatialIndex() override;
91
    virtual bool createAttributeIndex( int field ) override;
92
    virtual QgsVectorDataProvider::Capabilities capabilities() const override;
93
    virtual void setEncoding( const QString &e ) override;
94
    virtual bool enterUpdateMode() override { return _enterUpdateMode(); }
95
    virtual bool leaveUpdateMode() override;
96
    virtual bool isSaveAndLoadStyleToDatabaseSupported() const override;
97
    QString fileVectorFilters() const override;
98
    //! Return a string containing the available database drivers
99
    QString databaseDrivers() const;
100
    //! Return a string containing the available directory drivers
101
    QString protocolDrivers() const;
102
    //! Return a string containing the available protocol drivers
103
    QString directoryDrivers() const;
104

    
105
    bool isValid() const override;
106
    QVariant minimumValue( int index ) const override;
107
    QVariant maximumValue( int index ) const override;
108
    virtual QSet< QVariant > uniqueValues( int index, int limit = -1 ) const override;
109
    virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
110
        QgsFeedback *feedback = nullptr ) const override;
111

    
112
    QString name() const override;
113
    QString description() const override;
114
    virtual bool doesStrictFeatureTypeCheck() const override;
115

    
116
    //! Return OGR geometry type
117
    static OGRwkbGeometryType getOgrGeomType( OGRLayerH ogrLayer );
118

    
119
    //! Get single flatten geometry type
120
    static OGRwkbGeometryType ogrWkbSingleFlatten( OGRwkbGeometryType type );
121

    
122
    QString layerName() const { return mLayerName; }
123

    
124
    QString filePath() const { return mFilePath; }
125

    
126
    int layerIndex() const { return mLayerIndex; }
127

    
128
    QByteArray quotedIdentifier( const QByteArray &field ) const;
129

    
130
    /**
131
     * A forced reload invalidates the underlying connection.
132
     * E.g. in case a shapefile is replaced, the old file will be closed
133
     * and the new file will be opened.
134
     */
135
    void forceReload() override;
136
    void reloadData() override;
137

    
138
  protected:
139
    //! Loads fields from input file to member attributeFields
140
    void loadFields();
141

    
142
    //! Find out the number of features of the whole layer
143
    void recalculateFeatureCount();
144

    
145
    //! Tell OGR, which fields to fetch in nextFeature/featureAtId (ie. which not to ignore)
146
    void setRelevantFields( bool fetchGeometry, const QgsAttributeList &fetchAttributes );
147

    
148
    //! Convert a QgsField to work with OGR
149
    static bool convertField( QgsField &field, const QTextCodec &encoding );
150

    
151
    //! Clean shapefile from features which are marked as deleted
152
    void repack();
153

    
154
    //! Invalidate extent and optionally force its low level recomputation
155
    void invalidateCachedExtent( bool bForceRecomputeExtent );
156

    
157
    enum OpenMode
158
    {
159
      OpenModeInitial,
160
      OpenModeSameAsCurrent,
161
      OpenModeForceReadOnly,
162
      OpenModeForceUpdate,
163
      OpenModeForceUpdateRepackOff
164
    };
165

    
166
    void open( OpenMode mode );
167
    void close();
168

    
169
    bool _enterUpdateMode( bool implicit = false );
170

    
171
  private:
172
    unsigned char *getGeometryPointer( OGRFeatureH fet );
173
    QString ogrWkbGeometryTypeName( OGRwkbGeometryType type ) const;
174

    
175
    //! Starts a transaction if possible and return true in that case
176
    bool startTransaction();
177

    
178
    //! Commits a transaction
179
    bool commitTransaction();
180

    
181
    void addSubLayerDetailsToSubLayerList( int i, QgsOgrLayer *layer ) const;
182

    
183
    QgsFields mAttributeFields;
184

    
185
    //! Map of field index to default value
186
    QMap<int, QString> mDefaultValues;
187

    
188
    bool mFirstFieldIsFid = false;
189
    mutable OGREnvelope *mExtent = nullptr;
190
    bool mForceRecomputeExtent = false;
191

    
192
    /**
193
     * This member variable receives the same value as extent_
194
     in the method QgsOgrProvider::extent(). The purpose is to prevent a memory leak*/
195
    mutable QgsRectangle mExtentRect;
196

    
197
    //! Current working layer (might be a SQL result layer if mSubsetString is set)
198
    QgsOgrLayer *mOgrLayer = nullptr;
199

    
200
    //! Original layer (not a SQL result layer)
201
    QgsOgrLayer *mOgrOrigLayer = nullptr;
202

    
203
    //! path to filename
204
    QString mFilePath;
205

    
206
    //! layer name
207
    QString mLayerName;
208

    
209
    //! layer index
210
    int mLayerIndex = 0;
211

    
212
    //! was a sub layer requested?
213
    bool mIsSubLayer = false;
214

    
215
    /**
216
     * Optional geometry type for layers with multiple geometries,
217
     *  otherwise wkbUnknown. This type is always flatten (2D) and single, it means
218
     *  that 2D, 25D, single and multi types are mixed in one sublayer */
219
    OGRwkbGeometryType mOgrGeometryTypeFilter = wkbUnknown;
220

    
221
    //! current spatial filter
222
    QgsRectangle mFetchRect;
223

    
224
    //! String used to define a subset of the layer
225
    QString mSubsetString;
226

    
227
    // Friendly name of the GDAL Driver that was actually used to open the layer
228
    QString mGDALDriverName;
229

    
230
    bool mValid = false;
231

    
232
    OGRwkbGeometryType mOGRGeomType = wkbUnknown;
233
    long mFeaturesCounted = QgsVectorDataProvider::Uncounted;
234

    
235
    mutable QStringList mSubLayerList;
236

    
237
    bool addFeaturePrivate( QgsFeature &f, QgsFeatureSink::Flags flags );
238
    //! Deletes one feature
239
    bool deleteFeature( QgsFeatureId id );
240

    
241
    //! Calls OGR_L_SyncToDisk and recreates the spatial index if present
242
    bool syncToDisc();
243

    
244
    friend class QgsOgrFeatureSource;
245

    
246
    //! Whether the file is opened in write mode
247
    bool mWriteAccess = false;
248

    
249
    //! Whether the file can potentially be opened in write mode (but not necessarily currently)
250
    bool mWriteAccessPossible = false;
251

    
252
    //! Whether the open mode of the datasource changes w.r.t calls to enterUpdateMode() / leaveUpdateMode()
253
    bool mDynamicWriteAccess = false;
254

    
255
    bool mShapefileMayBeCorrupted = false;
256

    
257
    //! Converts the geometry to the layer type if necessary. Takes ownership of the passed geometry
258
    OGRGeometryH ConvertGeometryIfNecessary( OGRGeometryH );
259

    
260
    int mUpdateModeStackDepth = 0;
261

    
262
    bool mDeferRepack = false;
263

    
264
    void computeCapabilities();
265

    
266
    QgsVectorDataProvider::Capabilities mCapabilities;
267

    
268
    bool doInitialActionsForEdition();
269
};
270

    
271
/**
272
  \class QgsOgrProviderUtils
273
  \brief Utility class with static methods
274
  */
275
class QgsOgrProviderUtils
276
{
277
    friend class QgsOgrLayer;
278

    
279
    //! Identifies a dataset by name, updateMode and options
280
    class DatasetIdentification
281
    {
282
        QString toString() const;
283

    
284
      public:
285
        QString dsName;
286
        bool    updateMode = false;
287
        QStringList options;
288
        DatasetIdentification() {}
289

    
290
        bool operator< ( const DatasetIdentification &other ) const;
291
    };
292

    
293
    //! GDAL dataset objects and layers in use in it
294
    class DatasetWithLayers
295
    {
296
      public:
297
        QMutex         mutex;
298
        GDALDatasetH   hDS = nullptr;
299
        QMap<QString, QgsOgrLayer *>  setLayers;
300
        int            refCount = 0;
301

    
302
        DatasetWithLayers(): mutex( QMutex::Recursive ) {}
303
    };
304

    
305
    //! Global mutex for QgsOgrProviderUtils
306
    static QMutex globalMutex;
307

    
308
    //! Map dataset identification to a list of corresponding DatasetWithLayers*
309
    static QMap< DatasetIdentification, QList<DatasetWithLayers *> > mapSharedDS;
310

    
311
    //! Map a dataset name to the number of opened GDAL dataset objects on it (if opened with GDALOpenWrapper, only for GPKG)
312
    static QMap< QString, int > mapCountOpenedDS;
313

    
314
    //! Map a dataset handle to its update open mode (if opened with GDALOpenWrapper, only for GPKG)
315
    static QMap< GDALDatasetH, bool> mapDSHandleToUpdateMode;
316

    
317
    //! Map a dataset name to its last modified data
318
    static QMap< QString, QDateTime > mapDSNameToLastModifiedDate;
319

    
320
    static bool canUseOpenedDatasets( const QString &dsName );
321

    
322
  public:
323
    static void setRelevantFields( OGRLayerH ogrLayer, int fieldCount, bool fetchGeometry, const QgsAttributeList &fetchAttributes, bool firstAttrIsFid );
324
    static OGRLayerH setSubsetString( OGRLayerH layer, GDALDatasetH ds, QTextCodec *encoding, const QString &subsetString, bool &origFidAdded );
325
    static QByteArray quotedIdentifier( QByteArray field, const QString &driverName );
326

    
327
    /**
328
     * Quote a value for placement in a SQL string.
329
     */
330
    static QString quotedValue( const QVariant &value );
331

    
332
    //! Wrapper for GDALOpenEx() that does a few lower level actions. Should be strictly paired with GDALCloseWrapper()
333
    static GDALDatasetH GDALOpenWrapper( const char *pszPath, bool bUpdate, char **papszOpenOptionsIn, GDALDriverH *phDriver );
334

    
335
    //! Wrapper for GDALClose()
336
    static void GDALCloseWrapper( GDALDatasetH mhDS );
337

    
338
    //! Open a layer given by name, potentially reusing an existing GDALDatasetH if it doesn't already use that layer. release() should be called when done with the object
339
    static QgsOgrLayer *getLayer( const QString &dsName,
340
                                  const QString &layerName,
341
                                  QString &errCause );
342

    
343

    
344
    //! Open a layer given by name, potentially reusing an existing GDALDatasetH if it has been opened with the same (updateMode, options) tuple and doesn't already use that layer. release() should be called when done with the object
345
    static QgsOgrLayer *getLayer( const QString &dsName,
346
                                  bool updateMode,
347
                                  const QStringList &options,
348
                                  const QString &layerName,
349
                                  QString &errCause );
350

    
351
    //! Open a layer given by index, potentially reusing an existing GDALDatasetH if it doesn't already use that layer. release() should be called when done with the object
352
    static QgsOgrLayer *getLayer( const QString &dsName,
353
                                  int layerIndex,
354
                                  QString &errCause );
355

    
356
    //! Open a layer given by index, potentially reusing an existing GDALDatasetH if it has been opened with the same (updateMode, options) tuple and doesn't already use that layer. release() should be called when done with the object
357
    static QgsOgrLayer *getLayer( const QString &dsName,
358
                                  bool updateMode,
359
                                  const QStringList &options,
360
                                  int layerIndex,
361
                                  QString &errCause );
362

    
363
    //! Return a QgsOgrLayer* with a SQL result layer
364
    static QgsOgrLayer *getSqlLayer( QgsOgrLayer *baseLayer, OGRLayerH hSqlLayer, const QString &sql );
365

    
366
    //! Release a QgsOgrLayer*
367
    static void release( QgsOgrLayer *&layer );
368

    
369
    //! Make sure that the existing pool of opened datasets on dsName is not accessible for new getLayer() attempts
370
    static void invalidateCachedDatasets( const QString &dsName );
371

    
372
    //! Return the string to provide to QgsOgrConnPool::instance() methods
373
    static QString connectionPoolId( const QString &dataSourceURI );
374
};
375

    
376

    
377
/**
378
  \class QgsOgrFeatureDefn
379
  \brief Wrap a OGRFieldDefnH object in a thread-safe way
380
  */
381
class QgsOgrFeatureDefn
382
{
383
    friend class QgsOgrLayer;
384

    
385
    OGRFeatureDefnH hDefn = nullptr;
386
    QgsOgrLayer *layer = nullptr;
387

    
388
    QgsOgrFeatureDefn();
389
    ~QgsOgrFeatureDefn();
390

    
391
    OGRFeatureDefnH get();
392
    QMutex &mutex();
393

    
394
  public:
395

    
396
    //! Wrapper of OGR_FD_GetFieldCount
397
    int GetFieldCount();
398

    
399
    //! Wrapper of OGR_FD_GetFieldDefn
400
    OGRFieldDefnH GetFieldDefn( int );
401

    
402
    //! Wrapper of OGR_FD_GetFieldIndex
403
    int GetFieldIndex( const QByteArray & );
404

    
405
    //! Wrapper of OGR_FD_GetGeomFieldCount
406
    int GetGeomFieldCount();
407

    
408
    //! Wrapper of OGR_FD_GetGeomFieldDefn
409
    OGRGeomFieldDefnH GetGeomFieldDefn( int idx );
410

    
411
    //! Wrapper of OGR_FD_GetGeomType
412
    OGRwkbGeometryType GetGeomType();
413

    
414
    //! Wrapper of OGR_F_Create
415
    OGRFeatureH CreateFeature();
416
};
417

    
418
/**
419
  \class QgsOgrLayer
420
  \brief Wrap a OGRLayerH object in a thread-safe way
421
  */
422
class QgsOgrLayer
423
{
424
    friend class QgsOgrFeatureDefn;
425
    friend class QgsOgrProviderUtils;
426

    
427
    QgsOgrProviderUtils::DatasetIdentification ident;
428
    bool isSqlLayer = false;
429
    QString layerName;
430
    QString sql;
431
    QgsOgrProviderUtils::DatasetWithLayers *ds = nullptr;
432
    OGRLayerH hLayer = nullptr;
433
    QgsOgrFeatureDefn oFDefn;
434

    
435
    QgsOgrLayer();
436
    ~QgsOgrLayer();
437

    
438
    static QgsOgrLayer *CreateForLayer(
439
      const QgsOgrProviderUtils::DatasetIdentification &ident,
440
      const QString &layerName,
441
      QgsOgrProviderUtils::DatasetWithLayers *ds,
442
      OGRLayerH hLayer );
443

    
444
    static QgsOgrLayer *CreateForSql(
445
      const QgsOgrProviderUtils::DatasetIdentification &ident,
446
      const QString &sql,
447
      QgsOgrProviderUtils::DatasetWithLayers *ds,
448
      OGRLayerH hLayer );
449

    
450
    QMutex &mutex() { return ds->mutex; }
451

    
452
  public:
453

    
454
    //! Return GDALDriverH object for current dataset
455
    GDALDriverH driver();
456

    
457
    //! Return driver name for current dataset
458
    QString driverName();
459

    
460
    //! Return current dataset name
461
    const QString &datasetName() const { return ident.dsName; }
462

    
463
    //! Return dataset open mode
464
    bool updateMode() const { return ident.updateMode; }
465

    
466
    //! Return dataset open options
467
    const QStringList &options() const { return ident.options; }
468

    
469
    //! Return layer name
470
    QByteArray name();
471

    
472
    //! Wrapper of OGR_L_GetLayerCount
473
    int GetLayerCount();
474

    
475
    //! Wrapper of OGR_L_GetLayerCount
476
    QByteArray GetFIDColumn();
477

    
478
    //! Wrapper of OGR_L_GetLayerCount
479
    OGRSpatialReferenceH GetSpatialRef();
480

    
481
    //! Wrapper of OGR_L_GetLayerCount
482
    void ResetReading();
483

    
484
    //! Wrapper of OGR_L_GetLayerCount
485
    OGRFeatureH GetNextFeature();
486

    
487
    //! Wrapper of OGR_L_GetLayerCount
488
    OGRFeatureH GetFeature( GIntBig fid );
489

    
490
    //! Wrapper of OGR_L_GetLayerCount
491
    QgsOgrFeatureDefn &GetLayerDefn();
492

    
493
    //! Wrapper of OGR_L_GetLayerCount
494
    GIntBig GetFeatureCount( bool force = false );
495

    
496
    //! Wrapper of OGR_L_GetLayerCount
497
    OGRErr GetExtent( OGREnvelope *psExtent, bool bForce );
498

    
499
    //! Wrapper of OGR_L_GetLayerCount
500
    OGRErr CreateFeature( OGRFeatureH hFeature );
501

    
502
    //! Wrapper of OGR_L_GetLayerCount
503
    OGRErr SetFeature( OGRFeatureH hFeature );
504

    
505
    //! Wrapper of OGR_L_GetLayerCount
506
    OGRErr DeleteFeature( GIntBig fid );
507

    
508
    //! Wrapper of OGR_L_GetLayerCount
509
    OGRErr CreateField( OGRFieldDefnH hFieldDefn, bool bStrict );
510

    
511
    //! Wrapper of OGR_L_GetLayerCount
512
    OGRErr DeleteField( int iField );
513

    
514
    //! Wrapper of OGR_L_GetLayerCount
515
    OGRErr AlterFieldDefn( int iField, OGRFieldDefnH hNewFieldDefn, int flags );
516

    
517
    //! Wrapper of OGR_L_GetLayerCount
518
    int TestCapability( const char * );
519

    
520
    //! Wrapper of OGR_L_GetLayerCount
521
    OGRErr StartTransaction();
522

    
523
    //! Wrapper of OGR_L_GetLayerCount
524
    OGRErr CommitTransaction();
525

    
526
    //! Wrapper of OGR_L_GetLayerCount
527
    OGRErr RollbackTransaction();
528

    
529
    //! Wrapper of OGR_L_GetLayerCount
530
    OGRErr SyncToDisk();
531

    
532
    //! Wrapper of OGR_L_GetLayerCount
533
    OGRGeometryH GetSpatialFilter();
534

    
535
    //! Wrapper of OGR_L_GetLayerCount
536
    void SetSpatialFilter( OGRGeometryH );
537

    
538
    //! Return native GDALDatasetH object with the mutex to lock when using it
539
    GDALDatasetH getDatasetHandleAndMutex( QMutex *&mutex );
540

    
541
    //! Return native OGRLayerH object with the mutex to lock when using it
542
    OGRLayerH getHandleAndMutex( QMutex *&mutex );
543

    
544
    //! Wrapper of GDALDatasetReleaseResultSet( GDALDatasetExecuteSQL( ... ) )
545
    void ExecuteSQLNoReturn( const QByteArray &sql );
546

    
547
    //! Wrapper of GDALDatasetExecuteSQL(). Returned layer must be released with QgsOgrProviderUtils::release()
548
    QgsOgrLayer *ExecuteSQL( const QByteArray &sql );
549
};
550

    
551
// clazy:excludeall=qstring-allocations
552

    
553
#endif // QGSOGRPROVIDER_H