Skip to content
Permalink
Browse files

Reuse QgsPostgresConn to prevent deadlock

QgsPostgresProviderConnection::executeSqlPrivate() has a nested
call to itself which may cause a deadlock when the connectionpool is
exhausted:

Two active threads can acquire a Postgres connection at the start of
executeSqlPrivate() and end up both waiting to acquire the second
connection.

(cherry picked from commit 3e862c4)
  • Loading branch information
tomtor authored and nyalldawson committed Nov 20, 2020
1 parent d1f3f00 commit 19e2758e6fc290aaa1e760dddf99c33ada6a37ba
@@ -198,7 +198,7 @@ QList<QVariantList> QgsPostgresProviderConnection::executeSql( const QString &sq
return executeSqlPrivate( sql, true, feedback );
}

QList<QVariantList> QgsPostgresProviderConnection::executeSqlPrivate( const QString &sql, bool resolveTypes, QgsFeedback *feedback ) const
QList<QVariantList> QgsPostgresProviderConnection::executeSqlPrivate( const QString &sql, bool resolveTypes, QgsFeedback *feedback, QgsPostgresConn *pgconn ) const
{
QList<QVariantList> results;

@@ -209,7 +209,7 @@ QList<QVariantList> QgsPostgresProviderConnection::executeSqlPrivate( const QStr
}

const QgsDataSourceUri dsUri { uri() };
QgsPostgresConn *conn = QgsPostgresConnPool::instance()->acquireConnection( dsUri.connectionInfo( false ) );
QgsPostgresConn *conn = pgconn ? pgconn : QgsPostgresConnPool::instance()->acquireConnection( dsUri.connectionInfo( false ) );
if ( !conn )
{
throw QgsProviderConnectionException( QObject::tr( "Connection failed: %1" ).arg( uri() ) );
@@ -269,7 +269,7 @@ QList<QVariantList> QgsPostgresProviderConnection::executeSqlPrivate( const QStr
break;
}
const Oid oid { res.PQftype( rowIdx ) };
QList<QVariantList> typeRes { executeSqlPrivate( QStringLiteral( "SELECT typname FROM pg_type WHERE oid = %1" ).arg( oid ), false ) };
QList<QVariantList> typeRes { executeSqlPrivate( QStringLiteral( "SELECT typname FROM pg_type WHERE oid = %1" ).arg( oid ), false, nullptr, conn ) };
// Set the default to string
QVariant::Type vType { QVariant::Type::String };
if ( typeRes.size() > 0 && typeRes.first().size() > 0 )
@@ -357,7 +357,8 @@ QList<QVariantList> QgsPostgresProviderConnection::executeSqlPrivate( const QStr
results.push_back( row );
}
}
QgsPostgresConnPool::instance()->releaseConnection( conn );
if ( ! pgconn )
QgsPostgresConnPool::instance()->releaseConnection( conn );
if ( ! errCause.isEmpty() )
{
throw QgsProviderConnectionException( errCause );
@@ -61,7 +61,7 @@ class QgsPostgresProviderConnection : public QgsAbstractDatabaseProviderConnecti

private:

QList<QVariantList> executeSqlPrivate( const QString &sql, bool resolveTypes = true, QgsFeedback *feedback = nullptr ) const;
QList<QVariantList> executeSqlPrivate( const QString &sql, bool resolveTypes = true, QgsFeedback *feedback = nullptr, class QgsPostgresConn *pgconn = nullptr ) const;
void setDefaultCapabilities();
void dropTablePrivate( const QString &schema, const QString &name ) const;
void renameTablePrivate( const QString &schema, const QString &name, const QString &newName ) const;

0 comments on commit 19e2758

Please sign in to comment.
You can’t perform that action at this time.