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