Skip to content

Commit

Permalink
Fix query layers from SQL window trailing semicolon
Browse files Browse the repository at this point in the history
Fix #56993
  • Loading branch information
elpaso committed Jan 22, 2025
1 parent ef0dd03 commit 1de194a
Show file tree
Hide file tree
Showing 10 changed files with 32 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,8 @@ Checks if ``capability`` is supported.





};

QFlags<QgsAbstractDatabaseProviderConnection::Capability> operator|(QgsAbstractDatabaseProviderConnection::Capability f1, QFlags<QgsAbstractDatabaseProviderConnection::Capability> f2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,8 @@ Checks if ``capability`` is supported.





};

QFlags<QgsAbstractDatabaseProviderConnection::Capability> operator|(QgsAbstractDatabaseProviderConnection::Capability f1, QFlags<QgsAbstractDatabaseProviderConnection::Capability> f2);
Expand Down
2 changes: 1 addition & 1 deletion src/core/providers/ogr/qgsogrproviderconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ QgsVectorLayer *QgsOgrProviderConnection::createSqlVectorLayer( const QgsAbstrac
QgsProviderMetadata *providerMetadata { QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) };
Q_ASSERT( providerMetadata );
QMap<QString, QVariant> decoded = providerMetadata->decodeUri( uri() );
decoded[ QStringLiteral( "subset" ) ] = options.sql;
decoded[ QStringLiteral( "subset" ) ] = sanitizeSqlForQueryLayer( options.sql ) ;
return new QgsVectorLayer( providerMetadata->encodeUri( decoded ), options.layerName.isEmpty() ? QStringLiteral( "QueryLayer" ) : options.layerName, providerKey() );
}

Expand Down
10 changes: 10 additions & 0 deletions src/core/providers/qgsabstractdatabaseproviderconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ void QgsAbstractDatabaseProviderConnection::checkCapability( Qgis::DatabaseProvi
}
}

QString QgsAbstractDatabaseProviderConnection::sanitizeSqlForQueryLayer( const QString &sql ) const
{
QString sanitizedSql { sql.trimmed() };
while ( sanitizedSql.endsWith( ';' ) )
{
sanitizedSql.chop( 1 );
}
return sanitizedSql;
}

///@endcond

QString QgsAbstractDatabaseProviderConnection::providerKey() const
Expand Down
4 changes: 4 additions & 0 deletions src/core/providers/qgsabstractdatabaseproviderconnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,10 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
* \throws QgsProviderConnectionException if the capability is not supported
*/
void checkCapability( Qgis::DatabaseProviderConnectionCapability2 capability ) const;

//! Trim and remove any trailing semicolon
QString sanitizeSqlForQueryLayer( const QString &sql ) const SIP_SKIP;

///@endcond

Capabilities mCapabilities = Capabilities() SIP_SKIP;
Expand Down
2 changes: 1 addition & 1 deletion src/providers/hana/qgshanaproviderconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ QgsVectorLayer *QgsHanaProviderConnection::createSqlVectorLayer( const SqlVector
if ( !options.primaryKeyColumns.isEmpty() )
{
tUri.setKeyColumn( QgsHanaPrimaryKeyUtils::buildUriKey( options.primaryKeyColumns ) );
tUri.setTable( QStringLiteral( "(%1)" ).arg( options.sql ) );
tUri.setTable( QStringLiteral( "(%1)" ).arg( sanitizeSqlForQueryLayer( options.sql ) ) );
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion src/providers/oracle/qgsoracleproviderconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ QgsVectorLayer *QgsOracleProviderConnection::createSqlVectorLayer( const QgsAbst
if ( !options.primaryKeyColumns.isEmpty() )
{
tUri.setKeyColumn( options.primaryKeyColumns.join( ',' ) );
tUri.setTable( QStringLiteral( "(%1)" ).arg( options.sql ) );
tUri.setTable( QStringLiteral( "(%1)" ).arg( sanitizeSqlForQueryLayer( options.sql ) ) );
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions src/providers/postgres/qgspostgresproviderconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ QgsVectorLayer *QgsPostgresProviderConnection::createSqlVectorLayer( const SqlVe
if ( !options.primaryKeyColumns.isEmpty() )
{
tUri.setKeyColumn( options.primaryKeyColumns.join( ',' ) );
tUri.setTable( QStringLiteral( "(%1)" ).arg( options.sql ) );
tUri.setTable( QStringLiteral( "(%1)" ).arg( sanitizeSqlForQueryLayer( options.sql ) ) );
}
else
{
Expand All @@ -892,7 +892,7 @@ QgsVectorLayer *QgsPostgresProviderConnection::createSqlVectorLayer( const SqlVe
{
sqlId++;
}
tUri.setTable( QStringLiteral( "(SELECT row_number() over () AS _uid%1_, * FROM (%2\n) AS _subq_%3_\n)" ).arg( QString::number( pkId ), options.sql, QString::number( sqlId ) ) );
tUri.setTable( QStringLiteral( "(SELECT row_number() over () AS _uid%1_, * FROM (%2\n) AS _subq_%3_\n)" ).arg( QString::number( pkId ), sanitizeSqlForQueryLayer( options.sql ), QString::number( sqlId ) ) );
}

if ( !options.geometryColumn.isEmpty() )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ QgsVectorLayer *QgsSpatiaLiteProviderConnection::createSqlVectorLayer( const Qgs
QgsDataSourceUri tUri( uri() );

tUri.setSql( options.filter );
tUri.setTable( '(' + options.sql + ')' );
tUri.setTable( '(' + sanitizeSqlForQueryLayer( options.sql ) + ')' );

if ( !options.geometryColumn.isEmpty() )
{
Expand Down
8 changes: 8 additions & 0 deletions tests/src/python/test_qgsproviderconnection_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,14 @@ def testCreateSqlVectorLayer(self):
self.assertEqual(vl.name(), options.layerName)
self.assertEqual(vl.sourceCrs().authid(), crs)

# Test issue https://github.com/qgis/QGIS/issues/56993
options.sql += ';;;'
vl2 = conn.createSqlVectorLayer(options)
self.assertTrue(vl2.isValid())
self.assertTrue(vl2.isSqlQuery())
self.assertTrue(vl2.isSpatial())
del vl2

# Test that a database connection can be retrieved from an existing layer
vlconn = QgsMapLayerUtils.databaseConnection(vl)
self.assertIsNotNone(vlconn)
Expand Down

0 comments on commit 1de194a

Please sign in to comment.