@@ -48,6 +48,13 @@ email : sherman at mrcc.com
4848#include " qgsvectorlayerimport.h"
4949#include " qgslocalec.h"
5050
51+ #ifdef Q_OS_WIN
52+ #include < windows.h>
53+ #endif
54+ #ifdef Q_OS_LINUX
55+ #include < sys/vfs.h>
56+ #endif
57+
5158static const QString TEXT_PROVIDER_KEY = " ogr" ;
5259static const QString TEXT_PROVIDER_DESCRIPTION =
5360 QString ( " OGR data provider" )
@@ -382,11 +389,14 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
382389
383390QgsOgrProvider::~QgsOgrProvider ()
384391{
385- close ();
386392 QgsOgrConnPool::instance ()->unref ( dataSourceUri () );
387393 // We must also make sure to flush unusef cached connections so that
388394 // the file can be removed (#15137)
389395 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 ();
390400}
391401
392402QgsAbstractFeatureSource* QgsOgrProvider::featureSource () const
@@ -2903,6 +2913,125 @@ OGRDataSourceH QgsOgrProviderUtils::OGROpenWrapper( const char* pszPath, bool bU
29032913 return hDS;
29042914}
29052915
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+ }
29063035
29073036QByteArray QgsOgrProviderUtils::quotedIdentifier ( QByteArray field, const QString& ogrDriverName )
29083037{
@@ -3138,7 +3267,22 @@ void QgsOgrProvider::open( OpenMode mode )
31383267
31393268 // first try to open in update mode (unless specified otherwise)
31403269 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+ }
31413283 ogrDataSource = QgsOgrProviderUtils::OGROpenWrapper ( TO8F ( mFilePath ), true , &ogrDriver );
3284+ CPLSetThreadLocalConfigOption ( " OGR_SQLITE_JOURNAL" , NULL );
3285+ }
31423286
31433287 mValid = false ;
31443288 if ( ogrDataSource )
@@ -3268,7 +3412,7 @@ void QgsOgrProvider::close()
32683412
32693413 if ( ogrDataSource )
32703414 {
3271- OGR_DS_Destroy ( ogrDataSource );
3415+ QgsOgrProviderUtils::OGRDestroyWrapper ( ogrDataSource );
32723416 }
32733417 ogrDataSource = nullptr ;
32743418 ogrLayer = nullptr ;
0 commit comments