diff --git a/python/core/auto_generated/qgssqliteutils.sip.in b/python/core/auto_generated/qgssqliteutils.sip.in index df34c608bbf..bad63882f4b 100644 --- a/python/core/auto_generated/qgssqliteutils.sip.in +++ b/python/core/auto_generated/qgssqliteutils.sip.in @@ -52,6 +52,21 @@ Returns a string list of SQLite (and spatialite) system tables .. versionadded:: 3.8 %End + + static QSet uniqueFields( sqlite3 *connection, const QString &tableName, QString &errorMessage ); +%Docstring +Returns a list of field names for ``connection`` and ``tableName`` having a UNIQUE constraint, +fields that are part of a UNIQUE constraint that spans over multiple fields +are not returned. + +.. note:: + + the implementation is the same of GDAL but the test coverage is much + better in GDAL. + +.. versionadded:: 3.14 +%End + }; /************************************************************************ diff --git a/src/core/providers/ogr/qgsogrprovider.cpp b/src/core/providers/ogr/qgsogrprovider.cpp index be6a9ffd698..adf08c3f626 100644 --- a/src/core/providers/ogr/qgsogrprovider.cpp +++ b/src/core/providers/ogr/qgsogrprovider.cpp @@ -1105,13 +1105,15 @@ void QgsOgrProvider::loadFields() // This is a temporary solution until GDAL Unique support is available QSet uniqueFieldNames; + + if ( mGDALDriverName == QLatin1String( "GPKG" ) ) { sqlite3_database_unique_ptr dsPtr; - if ( dsPtr.open( mFilePath ) == SQLITE_OK ) + if ( dsPtr.open_v2( mFilePath, SQLITE_OPEN_READONLY, nullptr ) == SQLITE_OK ) { QString errMsg; - uniqueFieldNames = dsPtr.uniqueFields( mOgrLayer->name(), errMsg ); + uniqueFieldNames = QgsSqliteUtils::uniqueFields( dsPtr.get(), mOgrLayer->name(), errMsg ); if ( ! errMsg.isEmpty() ) { QgsMessageLog::logMessage( tr( "GPKG error searching for unique constraints on fields for table %1" ).arg( QString( mOgrLayer->name() ) ), tr( "OGR" ) ); diff --git a/src/core/qgssqliteutils.cpp b/src/core/qgssqliteutils.cpp index 414a837a0b1..234acb3c195 100644 --- a/src/core/qgssqliteutils.cpp +++ b/src/core/qgssqliteutils.cpp @@ -120,23 +120,23 @@ int sqlite3_database_unique_ptr::exec( const QString &sql, QString &errorMessage return ret; } -QSet sqlite3_database_unique_ptr::uniqueFields( const QString &tableName, QString &errorMessage ) +QSet QgsSqliteUtils::uniqueFields( sqlite3 *connection, const QString &tableName, QString &errorMessage ) { QSet uniqueFieldsResults; char *zErrMsg = 0; std::vector rows; - QString sql = sqlite3_mprintf( "select sql from sqlite_master where type='table' and name=%q", QgsSqliteUtils::quotedIdentifier( tableName ).toStdString().c_str() ); + QString sql = sqlite3_mprintf( "select sql from sqlite_master where type='table' and name=%q", quotedIdentifier( tableName ).toStdString().c_str() ); auto cb = [ ]( void *data /* Data provided in the 4th argument of sqlite3_exec() */, int /* The number of columns in row */, char **argv /* An array of strings representing fields in the row */, - char **/* An array of strings representing column names */ ) -> int + char ** /* An array of strings representing column names */ ) -> int { static_cast*>( data )->push_back( argv[0] ); return 0; }; - int rc = sqlite3_exec( get(), sql.toUtf8(), cb, ( void * )&rows, &zErrMsg ); + int rc = sqlite3_exec( connection, sql.toUtf8(), cb, ( void * )&rows, &zErrMsg ); if ( rc != SQLITE_OK ) { errorMessage = zErrMsg; @@ -172,7 +172,7 @@ QSet sqlite3_database_unique_ptr::uniqueFields( const QString &tableNam // Search indexes: sql = sqlite3_mprintf( "SELECT sql FROM sqlite_master WHERE type='index' AND" " tbl_name='%q' AND sql LIKE 'CREATE UNIQUE INDEX%%'" ); - rc = sqlite3_exec( get(), sql.toUtf8(), cb, ( void * )&rows, &zErrMsg ); + rc = sqlite3_exec( connection, sql.toUtf8(), cb, ( void * )&rows, &zErrMsg ); if ( rc != SQLITE_OK ) { errorMessage = zErrMsg; diff --git a/src/core/qgssqliteutils.h b/src/core/qgssqliteutils.h index b6fb2eeb7d4..f5ef5099a52 100644 --- a/src/core/qgssqliteutils.h +++ b/src/core/qgssqliteutils.h @@ -154,15 +154,6 @@ class CORE_EXPORT sqlite3_database_unique_ptr : public std::unique_ptr< sqlite3, */ int exec( const QString &sql, QString &errorMessage SIP_OUT ) const; - /** - * Returns a list of field names for \a tableName having a UNIQUE constraint, - * fields that are part of a UNIQUE constraint that spans over multiple fields - * are not returned. - * \note the implementation is the same of GDAL but the test coverage is much - * better in GDAL. - * \since QGIS 3.14 - */ - QSet uniqueFields( const QString &tableName, QString &errorMessage ); }; /** @@ -210,6 +201,17 @@ class CORE_EXPORT QgsSqliteUtils * \since QGIS 3.8 */ static QStringList systemTables(); + + /** + * Returns a list of field names for \a connection and \a tableName having a UNIQUE constraint, + * fields that are part of a UNIQUE constraint that spans over multiple fields + * are not returned. + * \note the implementation is the same of GDAL but the test coverage is much + * better in GDAL. + * \since QGIS 3.14 + */ + static QSet uniqueFields( sqlite3 *connection, const QString &tableName, QString &errorMessage ); + }; #endif // QGSSQLITEUTILS_H diff --git a/src/providers/spatialite/qgsspatialiteprovider.cpp b/src/providers/spatialite/qgsspatialiteprovider.cpp index dd791edc9c9..97912cdaaaf 100644 --- a/src/providers/spatialite/qgsspatialiteprovider.cpp +++ b/src/providers/spatialite/qgsspatialiteprovider.cpp @@ -913,15 +913,11 @@ void QgsSpatiaLiteProvider::fetchConstraints() // Use the same logic implemented in GDAL for GPKG QSet uniqueFieldNames; { - sqlite3_database_unique_ptr dsPtr; - if ( dsPtr.open( mSqlitePath ) == SQLITE_OK ) + QString errMsg; + uniqueFieldNames = QgsSqliteUtils::uniqueFields( mSqliteHandle, mTableName, errMsg ); + if ( ! errMsg.isEmpty() ) { - QString errMsg; - uniqueFieldNames = dsPtr.uniqueFields( mTableName, errMsg ); - if ( ! errMsg.isEmpty() ) - { - QgsMessageLog::logMessage( tr( "Error searching for unique constraints on fields for table %1" ).arg( mTableName ), tr( "spatialite" ) ); - } + QgsMessageLog::logMessage( tr( "Error searching for unique constraints on fields for table %1" ).arg( mTableName ), tr( "spatialite" ) ); } }