@@ -48,6 +48,13 @@ email : sherman at mrcc.com
48
48
#include " qgsvectorlayerimport.h"
49
49
#include " qgslocalec.h"
50
50
51
+ #ifdef Q_OS_WIN
52
+ #include < windows.h>
53
+ #endif
54
+ #ifdef Q_OS_LINUX
55
+ #include < sys/vfs.h>
56
+ #endif
57
+
51
58
static const QString TEXT_PROVIDER_KEY = " ogr" ;
52
59
static const QString TEXT_PROVIDER_DESCRIPTION =
53
60
QString ( " OGR data provider" )
@@ -382,11 +389,14 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
382
389
383
390
QgsOgrProvider::~QgsOgrProvider ()
384
391
{
385
- close ();
386
392
QgsOgrConnPool::instance ()->unref ( dataSourceUri () );
387
393
// We must also make sure to flush unusef cached connections so that
388
394
// the file can be removed (#15137)
389
395
QgsOgrConnPool::instance ()->invalidateConnections ( dataSourceUri () );
396
+
397
+ // Do that as last step for final cleanup that might be prevented by
398
+ // still opened datasets.
399
+ close ();
390
400
}
391
401
392
402
QgsAbstractFeatureSource* QgsOgrProvider::featureSource () const
@@ -2903,6 +2913,125 @@ OGRDataSourceH QgsOgrProviderUtils::OGROpenWrapper( const char* pszPath, bool bU
2903
2913
return hDS;
2904
2914
}
2905
2915
2916
+ static bool IsLocalFile ( const QString& path )
2917
+ {
2918
+ QString dirName ( QFileInfo ( path ).absolutePath () );
2919
+ // Start with the OS specific methods since the QT >= 5.4 method just
2920
+ // return a string and not an enumerated type.
2921
+ #if defined(Q_OS_WIN)
2922
+ if ( dirName.startsWith ( " \\\\ " ) )
2923
+ return false ;
2924
+ if ( dirName.length () >= 3 && dirName[1 ] == ' :' &&
2925
+ ( dirName[2 ] == ' \\ ' || dirName[2 ] == ' /' ) )
2926
+ {
2927
+ dirName.resize ( 3 );
2928
+ return GetDriveType ( dirName.toAscii ().constData () ) != DRIVE_REMOTE;
2929
+ }
2930
+ return true ;
2931
+ #elif defined(Q_OS_LINUX)
2932
+ struct statfs sStatFS ;
2933
+ if ( statfs ( dirName.toAscii ().constData (), &sStatFS ) == 0 )
2934
+ {
2935
+ // Codes from http://man7.org/linux/man-pages/man2/statfs.2.html
2936
+ if ( sStatFS .f_type == 0x6969 /* NFS */ ||
2937
+ sStatFS .f_type == 0x517b /* SMB */ ||
2938
+ sStatFS .f_type == 0xff534d42 /* CIFS */ )
2939
+ {
2940
+ return false ;
2941
+ }
2942
+ }
2943
+ return true ;
2944
+ #elif QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
2945
+ QStorageInfo info ( dirName );
2946
+ QString fileSystem ( info.fileSystemType () );
2947
+ QgsDebugMsg ( QString ( " Filesystem for %1 is %2" ).arg ( path ).arg ( fileSystem ) );
2948
+ return path != " nfs" && path != " smbfs" ;
2949
+ #else
2950
+ return true ;
2951
+ #endif
2952
+ }
2953
+
2954
+ void QgsOgrProviderUtils::OGRDestroyWrapper ( OGRDataSourceH ogrDataSource )
2955
+ {
2956
+ if ( !ogrDataSource )
2957
+ return ;
2958
+ OGRSFDriverH ogrDriver = OGR_DS_GetDriver ( ogrDataSource );
2959
+ QString ogrDriverName = OGR_Dr_GetName ( ogrDriver );
2960
+ QString datasetName ( FROM8 ( OGR_DS_GetName ( ogrDataSource ) ) );
2961
+ if ( ogrDriverName == " GPKG" &&
2962
+ IsLocalFile ( datasetName ) &&
2963
+ !CPLGetConfigOption ( " OGR_SQLITE_JOURNAL" , NULL ) )
2964
+ {
2965
+ // We need to reset all iterators on layers, otherwise we will not
2966
+ // be able to change journal_mode.
2967
+ int layerCount = OGR_DS_GetLayerCount ( ogrDataSource );
2968
+ for ( int i = 0 ; i < layerCount; i ++ )
2969
+ {
2970
+ OGR_L_ResetReading ( OGR_DS_GetLayer ( ogrDataSource, i ) );
2971
+ }
2972
+
2973
+ CPLPushErrorHandler ( CPLQuietErrorHandler );
2974
+ QgsDebugMsg ( " GPKG: Trying to return to delete mode" );
2975
+ bool bSuccess = false ;
2976
+ OGRLayerH hSqlLyr = OGR_DS_ExecuteSQL ( ogrDataSource,
2977
+ " PRAGMA journal_mode = delete" ,
2978
+ NULL , NULL );
2979
+ if ( hSqlLyr != NULL )
2980
+ {
2981
+ OGRFeatureH hFeat = OGR_L_GetNextFeature ( hSqlLyr );
2982
+ if ( hFeat != NULL )
2983
+ {
2984
+ const char * pszRet = OGR_F_GetFieldAsString ( hFeat, 0 );
2985
+ bSuccess = EQUAL ( pszRet, " delete" );
2986
+ QgsDebugMsg ( QString ( " Return: %1" ).arg ( pszRet ) );
2987
+ OGR_F_Destroy ( hFeat );
2988
+ }
2989
+ }
2990
+ else if ( CPLGetLastErrorType () != CE_None )
2991
+ {
2992
+ QgsDebugMsg ( QString ( " Return: %1" ).arg ( CPLGetLastErrorMsg () ) );
2993
+ }
2994
+ OGR_DS_ReleaseResultSet ( ogrDataSource, hSqlLyr );
2995
+ CPLPopErrorHandler ();
2996
+ OGR_DS_Destroy ( ogrDataSource );
2997
+
2998
+ // This may have not worked if the file was opened in read-only mode,
2999
+ // so retry in update mode
3000
+ if ( !bSuccess )
3001
+ {
3002
+ QgsDebugMsg ( " GPKG: Trying again" );
3003
+ CPLSetThreadLocalConfigOption ( " OGR_SQLITE_JOURNAL" , " DELETE" );
3004
+ ogrDataSource = OGROpen ( TO8F ( datasetName ), TRUE , NULL );
3005
+ CPLSetThreadLocalConfigOption ( " OGR_SQLITE_JOURNAL" , NULL );
3006
+ if ( ogrDataSource )
3007
+ {
3008
+ #ifdef QGISDEBUG
3009
+ CPLPushErrorHandler ( CPLQuietErrorHandler );
3010
+ OGRLayerH hSqlLyr = OGR_DS_ExecuteSQL ( ogrDataSource,
3011
+ " PRAGMA journal_mode" ,
3012
+ NULL , NULL );
3013
+ CPLPopErrorHandler ();
3014
+ if ( hSqlLyr != NULL )
3015
+ {
3016
+ OGRFeatureH hFeat = OGR_L_GetNextFeature ( hSqlLyr );
3017
+ if ( hFeat != NULL )
3018
+ {
3019
+ const char * pszRet = OGR_F_GetFieldAsString ( hFeat, 0 );
3020
+ QgsDebugMsg ( QString ( " Return: %1" ).arg ( pszRet ) );
3021
+ OGR_F_Destroy ( hFeat );
3022
+ }
3023
+ OGR_DS_ReleaseResultSet ( ogrDataSource, hSqlLyr );
3024
+ }
3025
+ #endif
3026
+ OGR_DS_Destroy ( ogrDataSource );
3027
+ }
3028
+ }
3029
+ }
3030
+ else
3031
+ {
3032
+ OGR_DS_Destroy ( ogrDataSource );
3033
+ }
3034
+ }
2906
3035
2907
3036
QByteArray QgsOgrProviderUtils::quotedIdentifier ( QByteArray field, const QString& ogrDriverName )
2908
3037
{
@@ -3138,7 +3267,22 @@ void QgsOgrProvider::open( OpenMode mode )
3138
3267
3139
3268
// first try to open in update mode (unless specified otherwise)
3140
3269
if ( !openReadOnly )
3270
+ {
3271
+ if ( QFileInfo ( mFilePath ).suffix ().compare ( " gpkg" , Qt::CaseInsensitive ) == 0 &&
3272
+ IsLocalFile ( mFilePath ) &&
3273
+ !CPLGetConfigOption ( " OGR_SQLITE_JOURNAL" , NULL ) &&
3274
+ QSettings ().value ( " /qgis/walForSqlite3" , true ).toBool () )
3275
+ {
3276
+ // For GeoPackage, we force opening of the file in WAL (Write Ahead Log)
3277
+ // mode so as to avoid readers blocking writer(s), and vice-versa.
3278
+ // https://www.sqlite.org/wal.html
3279
+ // But only do that on a local file since WAL is advertized not to work
3280
+ // on network shares
3281
+ CPLSetThreadLocalConfigOption ( " OGR_SQLITE_JOURNAL" , " WAL" );
3282
+ }
3141
3283
ogrDataSource = QgsOgrProviderUtils::OGROpenWrapper ( TO8F ( mFilePath ), true , &ogrDriver );
3284
+ CPLSetThreadLocalConfigOption ( " OGR_SQLITE_JOURNAL" , NULL );
3285
+ }
3142
3286
3143
3287
mValid = false ;
3144
3288
if ( ogrDataSource )
@@ -3268,7 +3412,7 @@ void QgsOgrProvider::close()
3268
3412
3269
3413
if ( ogrDataSource )
3270
3414
{
3271
- OGR_DS_Destroy ( ogrDataSource );
3415
+ QgsOgrProviderUtils::OGRDestroyWrapper ( ogrDataSource );
3272
3416
}
3273
3417
ogrDataSource = nullptr ;
3274
3418
ogrLayer = nullptr ;
0 commit comments