mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-05 00:04:40 -05:00
UNIQUE fields detector for sqlite based providers
This is a temporary solution for OGR because we expect to use the native GDAL implementation in GDAL 3.2. For now a new method QgsSqliteUtils::uniqueFields used by spatialite and OGR/GPKG is used to detect UNIQUE constraints on single fields.
This commit is contained in:
parent
bb47d7f745
commit
fa7177a056
@ -52,6 +52,21 @@ Returns a string list of SQLite (and spatialite) system tables
|
|||||||
|
|
||||||
.. versionadded:: 3.8
|
.. versionadded:: 3.8
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
static QSet<QString> 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
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
|
|||||||
@ -1105,13 +1105,15 @@ void QgsOgrProvider::loadFields()
|
|||||||
|
|
||||||
// This is a temporary solution until GDAL Unique support is available
|
// This is a temporary solution until GDAL Unique support is available
|
||||||
QSet<QString> uniqueFieldNames;
|
QSet<QString> uniqueFieldNames;
|
||||||
|
|
||||||
|
|
||||||
if ( mGDALDriverName == QLatin1String( "GPKG" ) )
|
if ( mGDALDriverName == QLatin1String( "GPKG" ) )
|
||||||
{
|
{
|
||||||
sqlite3_database_unique_ptr dsPtr;
|
sqlite3_database_unique_ptr dsPtr;
|
||||||
if ( dsPtr.open( mFilePath ) == SQLITE_OK )
|
if ( dsPtr.open_v2( mFilePath, SQLITE_OPEN_READONLY, nullptr ) == SQLITE_OK )
|
||||||
{
|
{
|
||||||
QString errMsg;
|
QString errMsg;
|
||||||
uniqueFieldNames = dsPtr.uniqueFields( mOgrLayer->name(), errMsg );
|
uniqueFieldNames = QgsSqliteUtils::uniqueFields( dsPtr.get(), mOgrLayer->name(), errMsg );
|
||||||
if ( ! errMsg.isEmpty() )
|
if ( ! errMsg.isEmpty() )
|
||||||
{
|
{
|
||||||
QgsMessageLog::logMessage( tr( "GPKG error searching for unique constraints on fields for table %1" ).arg( QString( mOgrLayer->name() ) ), tr( "OGR" ) );
|
QgsMessageLog::logMessage( tr( "GPKG error searching for unique constraints on fields for table %1" ).arg( QString( mOgrLayer->name() ) ), tr( "OGR" ) );
|
||||||
|
|||||||
@ -120,23 +120,23 @@ int sqlite3_database_unique_ptr::exec( const QString &sql, QString &errorMessage
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<QString> sqlite3_database_unique_ptr::uniqueFields( const QString &tableName, QString &errorMessage )
|
QSet<QString> QgsSqliteUtils::uniqueFields( sqlite3 *connection, const QString &tableName, QString &errorMessage )
|
||||||
{
|
{
|
||||||
QSet<QString> uniqueFieldsResults;
|
QSet<QString> uniqueFieldsResults;
|
||||||
char *zErrMsg = 0;
|
char *zErrMsg = 0;
|
||||||
std::vector<std::string> rows;
|
std::vector<std::string> 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 = [ ](
|
auto cb = [ ](
|
||||||
void *data /* Data provided in the 4th argument of sqlite3_exec() */,
|
void *data /* Data provided in the 4th argument of sqlite3_exec() */,
|
||||||
int /* The number of columns in row */,
|
int /* The number of columns in row */,
|
||||||
char **argv /* An array of strings representing fields in the 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<std::vector<std::string>*>( data )->push_back( argv[0] );
|
static_cast<std::vector<std::string>*>( data )->push_back( argv[0] );
|
||||||
return 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 )
|
if ( rc != SQLITE_OK )
|
||||||
{
|
{
|
||||||
errorMessage = zErrMsg;
|
errorMessage = zErrMsg;
|
||||||
@ -172,7 +172,7 @@ QSet<QString> sqlite3_database_unique_ptr::uniqueFields( const QString &tableNam
|
|||||||
// Search indexes:
|
// Search indexes:
|
||||||
sql = sqlite3_mprintf( "SELECT sql FROM sqlite_master WHERE type='index' AND"
|
sql = sqlite3_mprintf( "SELECT sql FROM sqlite_master WHERE type='index' AND"
|
||||||
" tbl_name='%q' AND sql LIKE 'CREATE UNIQUE INDEX%%'" );
|
" 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 )
|
if ( rc != SQLITE_OK )
|
||||||
{
|
{
|
||||||
errorMessage = zErrMsg;
|
errorMessage = zErrMsg;
|
||||||
|
|||||||
@ -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;
|
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<QString> uniqueFields( const QString &tableName, QString &errorMessage );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,6 +201,17 @@ class CORE_EXPORT QgsSqliteUtils
|
|||||||
* \since QGIS 3.8
|
* \since QGIS 3.8
|
||||||
*/
|
*/
|
||||||
static QStringList systemTables();
|
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<QString> uniqueFields( sqlite3 *connection, const QString &tableName, QString &errorMessage );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QGSSQLITEUTILS_H
|
#endif // QGSSQLITEUTILS_H
|
||||||
|
|||||||
@ -913,15 +913,11 @@ void QgsSpatiaLiteProvider::fetchConstraints()
|
|||||||
// Use the same logic implemented in GDAL for GPKG
|
// Use the same logic implemented in GDAL for GPKG
|
||||||
QSet<QString> uniqueFieldNames;
|
QSet<QString> uniqueFieldNames;
|
||||||
{
|
{
|
||||||
sqlite3_database_unique_ptr dsPtr;
|
QString errMsg;
|
||||||
if ( dsPtr.open( mSqlitePath ) == SQLITE_OK )
|
uniqueFieldNames = QgsSqliteUtils::uniqueFields( mSqliteHandle, mTableName, errMsg );
|
||||||
|
if ( ! errMsg.isEmpty() )
|
||||||
{
|
{
|
||||||
QString errMsg;
|
QgsMessageLog::logMessage( tr( "Error searching for unique constraints on fields for table %1" ).arg( mTableName ), tr( "spatialite" ) );
|
||||||
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" ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user