Skip to content

Commit

Permalink
Reuse QgsPostgresConn to prevent deadlock
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tomtor committed Nov 17, 2020
1 parent 53f4161 commit 3e862c4
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 5 deletions.
9 changes: 5 additions & 4 deletions src/providers/postgres/qgspostgresproviderconnection.cpp
Expand Up @@ -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;

Expand All @@ -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() ) );
Expand Down Expand Up @@ -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 )
Expand Down Expand Up @@ -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 );
Expand Down
2 changes: 1 addition & 1 deletion src/providers/postgres/qgspostgresproviderconnection.h
Expand Up @@ -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;
Expand Down

0 comments on commit 3e862c4

Please sign in to comment.