mirror of
https://github.com/qgis/QGIS.git
synced 2025-03-01 00:46:20 -05:00
DB2 fixes for #20337
This commit is contained in:
parent
152b1b09ff
commit
c339dd49fb
@ -51,21 +51,11 @@ QgsDb2FeatureIterator::QgsDb2FeatureIterator( QgsDb2FeatureSource *source, bool
|
||||
|
||||
BuildStatement( request );
|
||||
|
||||
// connect to the database
|
||||
QString errMsg;
|
||||
mDatabase = QgsDb2Provider::getDatabase( mSource->mConnInfo, errMsg );
|
||||
|
||||
if ( !errMsg.isEmpty() )
|
||||
{
|
||||
QgsDebugMsg( "Failed to open database: " + errMsg );
|
||||
return;
|
||||
}
|
||||
|
||||
// create sql query
|
||||
mQuery.reset( new QSqlQuery( mDatabase ) );
|
||||
|
||||
// start selection
|
||||
rewind();
|
||||
// WARNING - we can't obtain the database connection now, as this method should be
|
||||
// run from the main thread, yet iteration can be done in a different thread.
|
||||
// This would result in failure, because QSqlDatabase instances cannot be used
|
||||
// from a different thread where they were created. Instead, we defer creation
|
||||
// of the database until the first feature is fetched.
|
||||
}
|
||||
|
||||
|
||||
@ -308,12 +298,30 @@ bool QgsDb2FeatureIterator::nextFeatureFilterExpression( QgsFeature &f )
|
||||
bool QgsDb2FeatureIterator::fetchFeature( QgsFeature &feature )
|
||||
{
|
||||
feature.setValid( false );
|
||||
if ( mClosed )
|
||||
|
||||
if ( !mDatabase.isValid() )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "iterator closed" ) );
|
||||
// No existing connection, so set it up now. It's safe to do here as we're now in
|
||||
// the thread were iteration is actually occurring.
|
||||
// connect to the database
|
||||
QString errMsg;
|
||||
QgsDebugMsg( QStringLiteral( "fetchFeature getDatabase" ) );
|
||||
mDatabase = QgsDb2Provider::getDatabase( mSource->mConnInfo, errMsg );
|
||||
QgsDebugMsg( QStringLiteral( "fetchFeature back from getDatabase" ) );
|
||||
if ( !errMsg.isEmpty() )
|
||||
{
|
||||
QgsDebugMsg( "Failed to open database: " + errMsg );
|
||||
return false;
|
||||
}
|
||||
|
||||
// create sql query
|
||||
mQuery.reset( new QSqlQuery( mDatabase ) );
|
||||
|
||||
// start selection
|
||||
if ( !rewind() )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !mQuery )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Read attempt on no query" ) );
|
||||
@ -402,7 +410,10 @@ bool QgsDb2FeatureIterator::fetchFeature( QgsFeature &feature )
|
||||
bool QgsDb2FeatureIterator::rewind()
|
||||
{
|
||||
if ( mClosed )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "iterator closed" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( mStatement.isEmpty() )
|
||||
{
|
||||
|
@ -186,16 +186,23 @@ QSqlDatabase QgsDb2Provider::getDatabase( const QString &connInfo, QString &errM
|
||||
connectionName = service;
|
||||
}
|
||||
QgsDebugMsg( "connectionName: " + connectionName );
|
||||
|
||||
// Starting with Qt 5.11, sharing the same connection between threads is not allowed.
|
||||
// We use a dedicated connection for each thread requiring access to the database,
|
||||
// using the thread address as connection name.
|
||||
const QString threadSafeConnectionName = dbConnectionName( connectionName );
|
||||
QgsDebugMsg( "threadSafeConnectionName: " + threadSafeConnectionName );
|
||||
|
||||
/* if new database connection */
|
||||
if ( !QSqlDatabase::contains( connectionName ) )
|
||||
if ( !QSqlDatabase::contains( threadSafeConnectionName ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "new connection. create new QODBC mapping" ) );
|
||||
db = QSqlDatabase::addDatabase( QStringLiteral( "QODBC3" ), connectionName );
|
||||
db = QSqlDatabase::addDatabase( QStringLiteral( "QODBC3" ), threadSafeConnectionName );
|
||||
}
|
||||
else /* if existing database connection */
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "found existing connection, use the existing one" ) );
|
||||
db = QSqlDatabase::database( connectionName );
|
||||
db = QSqlDatabase::database( threadSafeConnectionName );
|
||||
}
|
||||
db.setHostName( host );
|
||||
db.setPort( port.toInt() );
|
||||
@ -1747,6 +1754,14 @@ QGISEXTERN QgsVectorLayerExporter::ExportError createEmptyLayer(
|
||||
);
|
||||
}
|
||||
|
||||
QString QgsDb2Provider::dbConnectionName( const QString &name )
|
||||
{
|
||||
// Starting with Qt 5.11, sharing the same connection between threads is not allowed.
|
||||
// We use a dedicated connection for each thread requiring access to the database,
|
||||
// using the thread address as connection name.
|
||||
const QString threadAddress = QStringLiteral( ":0x%1" ).arg( QString::number( reinterpret_cast< quintptr >( QThread::currentThread() ), 16 ) );
|
||||
return name + threadAddress;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GUI
|
||||
|
||||
|
@ -118,6 +118,10 @@ class QgsDb2Provider : public QgsVectorDataProvider
|
||||
private:
|
||||
static void db2WkbTypeAndDimension( QgsWkbTypes::Type wkbType, QString &geometryType, int &dim );
|
||||
static QString db2TypeName( int typeId );
|
||||
/**
|
||||
* Returns a thread-safe connection name for use with QSqlDatabase
|
||||
*/
|
||||
static QString dbConnectionName( const QString &name );
|
||||
|
||||
QgsFields mAttributeFields; //fields
|
||||
QMap<int, QVariant> mDefaultValues;
|
||||
|
Loading…
x
Reference in New Issue
Block a user