Skip to content
Permalink
Browse files
Revert to conn pool
  • Loading branch information
elpaso committed Jul 6, 2021
1 parent eea1eb4 commit d81906959806ee67f77857f9536e99b4a4a9df77
@@ -80,8 +80,14 @@ Emitted when all rows have been fetched or when the fetching has been stopped
%End

void fetchMoreRows( qlonglong maxRows );
%Docstring
Emitted when more rows are requested
%End

void fetchingStarted();
%Docstring
Emitted when fetching of rows starts
%End

};

@@ -127,8 +127,10 @@ class CORE_EXPORT QgsQueryResultModel : public QAbstractTableModel
//! Emitted when all rows have been fetched or when the fetching has been stopped
void fetchingComplete();

//! Emitted when more rows are requested
void fetchMoreRows( qlonglong maxRows );

//! Emitted when fetching of rows starts
void fetchingStarted();

private:
@@ -207,24 +207,17 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsPostgresProviderConnection
return execSqlPrivate( sql, true, feedback );
}

QList<QVariantList> QgsPostgresProviderConnection::executeSqlPrivate( const QString &sql, bool resolveTypes, QgsFeedback *feedback, std::shared_ptr<QgsPostgresConn> pgconn ) const
QList<QVariantList> QgsPostgresProviderConnection::executeSqlPrivate( const QString &sql, bool resolveTypes, QgsFeedback *feedback, std::shared_ptr<QgsPoolPostgresConn> pgconn ) const
{
QStringList columnNames;
return execSqlPrivate( sql, resolveTypes, feedback, pgconn ).rows();
}

QgsAbstractDatabaseProviderConnection::QueryResult QgsPostgresProviderConnection::execSqlPrivate( const QString &sql, bool resolveTypes, QgsFeedback *feedback, std::shared_ptr<QgsPostgresConn> _pgconn ) const
QgsAbstractDatabaseProviderConnection::QueryResult QgsPostgresProviderConnection::execSqlPrivate( const QString &sql, bool resolveTypes, QgsFeedback *feedback, std::shared_ptr<QgsPoolPostgresConn> pgconn ) const
{

auto custom_deleter = [ ]( QgsPostgresConn * p )
{
p->unref();
};
std::unique_ptr<QgsPostgresConn, decltype( custom_deleter )> pgconn( new QgsPostgresConn( QgsDataSourceUri( uri() ).connectionInfo( false ), false /* readOnly */, false /* shared */, true /* transaction */ ), custom_deleter );

if ( ! pgconn )
{
throw QgsProviderConnectionException( QObject::tr( "Connection failed: %1" ).arg( uri() ) );
pgconn = std::make_shared<QgsPoolPostgresConn>( QgsDataSourceUri( uri() ).connectionInfo( false ) );
}

std::shared_ptr<QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator> iterator = std::make_shared<QgsPostgresProviderResultIterator>( resolveTypes );
@@ -236,144 +229,153 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsPostgresProviderConnection
return results;
}

QgsPostgresConn *conn = pgconn->get();

if ( feedback && feedback->isCanceled() )
{
return results;
}

// This is gross but I tried with both conn and a context QObject without success: the lambda is never called.
QMetaObject::Connection qtConnection;
if ( feedback )
{
qtConnection = QObject::connect( feedback, &QgsFeedback::canceled, [ &pgconn ]
{
if ( pgconn )
pgconn->PQCancel();
} );
}

std::unique_ptr<QgsPostgresResult> res = std::make_unique<QgsPostgresResult>( pgconn->PQexec( sql ) );

if ( feedback )
if ( ! conn )
{
QObject::disconnect( qtConnection );
}

QString errCause;
if ( pgconn->PQstatus() != CONNECTION_OK || ! res->result() )
{
errCause = QObject::tr( "Connection error: %1 returned %2 [%3]" )
.arg( sql ).arg( pgconn->PQstatus() )
.arg( pgconn->PQerrorMessage() );
throw QgsProviderConnectionException( QObject::tr( "Connection failed: %1" ).arg( uri() ) );
}
else
{
const QString err { pgconn->PQerrorMessage() };
if ( ! err.isEmpty() )

if ( feedback && feedback->isCanceled() )
{
errCause = QObject::tr( "SQL error: %1 returned %2 [%3]" )
.arg( sql )
.arg( pgconn->PQstatus() )
.arg( err );
return results;
}
}

const qlonglong numRows { res->PQntuples() };
// This is gross but I tried with both conn and a context QObject without success: the lambda is never called.
QMetaObject::Connection qtConnection;
if ( feedback )
{
qtConnection = QObject::connect( feedback, &QgsFeedback::canceled, [ &pgconn ]
{
if ( pgconn )
pgconn->get()->PQCancel();
} );
}

if ( numRows > 0 )
{
std::unique_ptr<QgsPostgresResult> res = std::make_unique<QgsPostgresResult>( conn->PQexec( sql ) );

// Get column names
for ( int rowIdx = 0; rowIdx < res->PQnfields(); rowIdx++ )
if ( feedback )
{
results.appendColumn( res->PQfname( rowIdx ) );
QObject::disconnect( qtConnection );
}

// Try to convert value types at least for basic simple types that can be directly mapped to Python
const int numFields { res->PQnfields() };
if ( resolveTypes )
QString errCause;
if ( conn->PQstatus() != CONNECTION_OK || ! res->result() )
{
// Collect oids
QStringList oids;
oids.reserve( numFields );
for ( int rowIdx = 0; rowIdx < numFields; rowIdx++ )
errCause = QObject::tr( "Connection error: %1 returned %2 [%3]" )
.arg( sql ).arg( conn->PQstatus() )
.arg( conn->PQerrorMessage() );
}
else
{
const QString err { conn->PQerrorMessage() };
if ( ! err.isEmpty() )
{
if ( feedback && feedback->isCanceled() )
{
break;
}
const QString oidStr { QString::number( res->PQftype( rowIdx ) ) };
oids.push_back( oidStr );
errCause = QObject::tr( "SQL error: %1 returned %2 [%3]" )
.arg( sql )
.arg( conn->PQstatus() )
.arg( err );
}
}

const qlonglong numRows { res->PQntuples() };

if ( numRows > 0 )
{

const QList<QVariantList> typesResolved( executeSqlPrivate( QStringLiteral( "SELECT oid, typname FROM pg_type WHERE oid IN (%1)" ).arg( oids.join( ',' ) ), false, nullptr ) );
QgsStringMap oidTypeMap;
for ( const auto &typeRes : std::as_const( typesResolved ) )
// Get column names
for ( int rowIdx = 0; rowIdx < res->PQnfields(); rowIdx++ )
{
const QString oid { typeRes.constLast().toString() };
if ( ! oidTypeMap.contains( oid ) )
{
oidTypeMap.insert( typeRes.constFirst().toString(), typeRes.constLast().toString() );
}
results.appendColumn( res->PQfname( rowIdx ) );
}

for ( int rowIdx = 0; rowIdx < numFields; rowIdx++ )
// Try to convert value types at least for basic simple types that can be directly mapped to Python
const int numFields { res->PQnfields() };
if ( resolveTypes )
{
static const QStringList intTypes = { QStringLiteral( "oid" ),
QStringLiteral( "int2" ),
QStringLiteral( "int4" ),
QStringLiteral( "int8" ),
};
static const QStringList floatTypes = { QStringLiteral( "float4" ),
QStringLiteral( "float8" ),
QStringLiteral( "numeric" )
};

const QString typName { oidTypeMap[ oids.at( rowIdx )] };
QVariant::Type vType { QVariant::Type::String };
if ( floatTypes.contains( typName ) )
// Collect oids
QStringList oids;
oids.reserve( numFields );
for ( int rowIdx = 0; rowIdx < numFields; rowIdx++ )
{
vType = QVariant::Double;
}
else if ( intTypes.contains( typName ) )
{
vType = QVariant::LongLong;
}
else if ( typName == QLatin1String( "date" ) )
{
vType = QVariant::Date;
}
else if ( typName.startsWith( QLatin1String( "timestamp" ) ) )
{
vType = QVariant::DateTime;
}
else if ( typName == QLatin1String( "time" ) )
{
vType = QVariant::Time;
}
else if ( typName == QLatin1String( "bool" ) )
{
vType = QVariant::Bool;
if ( feedback && feedback->isCanceled() )
{
break;
}
const QString oidStr { QString::number( res->PQftype( rowIdx ) ) };
oids.push_back( oidStr );
}
else if ( typName == QLatin1String( "char" ) )

const QList<QVariantList> typesResolved( executeSqlPrivate( QStringLiteral( "SELECT oid, typname FROM pg_type WHERE oid IN (%1)" ).arg( oids.join( ',' ) ), false, nullptr, pgconn ) );
QgsStringMap oidTypeMap;
for ( const auto &typeRes : std::as_const( typesResolved ) )
{
vType = QVariant::Char;
const QString oid { typeRes.constLast().toString() };
if ( ! oidTypeMap.contains( oid ) )
{
oidTypeMap.insert( typeRes.constFirst().toString(), typeRes.constLast().toString() );
}
}
else

for ( int rowIdx = 0; rowIdx < numFields; rowIdx++ )
{
// Just a warning, usually ok
QgsDebugMsgLevel( QStringLiteral( "Unhandled PostgreSQL type %1, assuming string" ).arg( typName ), 2 );
static const QStringList intTypes = { QStringLiteral( "oid" ),
QStringLiteral( "int2" ),
QStringLiteral( "int4" ),
QStringLiteral( "int8" ),
};
static const QStringList floatTypes = { QStringLiteral( "float4" ),
QStringLiteral( "float8" ),
QStringLiteral( "numeric" )
};

const QString typName { oidTypeMap[ oids.at( rowIdx )] };
QVariant::Type vType { QVariant::Type::String };
if ( floatTypes.contains( typName ) )
{
vType = QVariant::Double;
}
else if ( intTypes.contains( typName ) )
{
vType = QVariant::LongLong;
}
else if ( typName == QLatin1String( "date" ) )
{
vType = QVariant::Date;
}
else if ( typName.startsWith( QLatin1String( "timestamp" ) ) )
{
vType = QVariant::DateTime;
}
else if ( typName == QLatin1String( "time" ) )
{
vType = QVariant::Time;
}
else if ( typName == QLatin1String( "bool" ) )
{
vType = QVariant::Bool;
}
else if ( typName == QLatin1String( "char" ) )
{
vType = QVariant::Char;
}
else
{
// Just a warning, usually ok
QgsDebugMsgLevel( QStringLiteral( "Unhandled PostgreSQL type %1, assuming string" ).arg( typName ), 2 );
}
static_cast<QgsPostgresProviderResultIterator *>( iterator.get() )->typeMap[ rowIdx ] = vType;
}
static_cast<QgsPostgresProviderResultIterator *>( iterator.get() )->typeMap[ rowIdx ] = vType;
}
}
if ( ! errCause.isEmpty() )
{
throw QgsProviderConnectionException( errCause );
}
static_cast<QgsPostgresProviderResultIterator *>( iterator.get() )->result = std::move( res );
}
if ( ! errCause.isEmpty() )
{
throw QgsProviderConnectionException( errCause );
}
static_cast<QgsPostgresProviderResultIterator *>( iterator.get() )->result = std::move( res );
return results;
}

@@ -81,8 +81,8 @@ class QgsPostgresProviderConnection : public QgsAbstractDatabaseProviderConnecti

private:

QList<QVariantList> executeSqlPrivate( const QString &sql, bool resolveTypes = true, QgsFeedback *feedback = nullptr, std::shared_ptr< class QgsPostgresConn> pgconn = nullptr ) const;
QgsAbstractDatabaseProviderConnection::QueryResult execSqlPrivate( const QString &sql, bool resolveTypes = true, QgsFeedback *feedback = nullptr, std::shared_ptr< class QgsPostgresConn> pgconn = nullptr ) const;
QList<QVariantList> executeSqlPrivate( const QString &sql, bool resolveTypes = true, QgsFeedback *feedback = nullptr, std::shared_ptr< class QgsPoolPostgresConn > pgconn = nullptr ) const;
QgsAbstractDatabaseProviderConnection::QueryResult execSqlPrivate( const QString &sql, bool resolveTypes = true, QgsFeedback *feedback = nullptr, std::shared_ptr< class QgsPoolPostgresConn > 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 d819069

Please sign in to comment.