Skip to content

Commit 4009b2d

Browse files
committed
[postgres] Fix checkPrimaryKeyUnicity option
This provider option was linked to the project level option "Trust layer metadata..." which was implemented to speed up loading of large dataset by trusting extent read from metadata to avoid costly operations to determine the layer extent. Check PK unicity on the other hand has only effect on views and query layers and it is useful as an independent option to prevent loading of layers that have no PK (or the wrong one). But the operation of determine unicity of a values in a column can also be costly, so better to get control back to the user. Legacy default is preserved (the project-level "Trust..." option). Fixes #21839 Funded by RAAB.nl
1 parent 140ec61 commit 4009b2d

File tree

8 files changed

+88
-46
lines changed

8 files changed

+88
-46
lines changed

src/app/qgsprojectproperties.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,8 @@ void QgsProjectProperties::apply()
989989
// Set the project title
990990
QgsProject::instance()->setTitle( title() );
991991
QgsProject::instance()->setPresetHomePath( QDir::fromNativeSeparators( mProjectHomeLineEdit->text() ) );
992+
993+
// DB-related options
992994
QgsProject::instance()->setAutoTransaction( mAutoTransaction->isChecked() );
993995
QgsProject::instance()->setEvaluateDefaultValues( mEvaluateDefaultValues->isChecked() );
994996
QgsProject::instance()->setTrustLayerMetadata( mTrustProjectCheckBox->isChecked() );

src/core/qgsvectorlayer.cpp

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,24 +1560,8 @@ QString QgsVectorLayer::loadDefaultStyle( bool &resultFlag )
15601560
bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options )
15611561
{
15621562
mProviderKey = provider;
1563-
1564-
// primary key unicity is tested at construction time, so it has to be set
1565-
// before initializing postgres provider
1566-
QString checkUnicityKey = QStringLiteral( "checkPrimaryKeyUnicity" );
1567-
QString dataSource = mDataSource;
1568-
if ( provider.compare( QLatin1String( "postgres" ) ) == 0 )
1569-
{
1570-
QgsDataSourceUri uri( dataSource );
1571-
1572-
if ( uri.hasParam( checkUnicityKey ) )
1573-
uri.removeParam( checkUnicityKey );
1574-
1575-
uri.setParam( checkUnicityKey, mReadExtentFromXml ? "0" : "1" );
1576-
dataSource = uri.uri( false );
1577-
}
1578-
15791563
delete mDataProvider;
1580-
mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options ) );
1564+
mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, mDataSource, options ) );
15811565
if ( !mDataProvider )
15821566
{
15831567
mValid = false;
@@ -1635,15 +1619,7 @@ bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProv
16351619
if ( !lName.isEmpty() )
16361620
setName( lName );
16371621
}
1638-
16391622
QgsDebugMsgLevel( QStringLiteral( "Beautified layer name %1" ).arg( name() ), 3 );
1640-
1641-
// deal with unnecessary schema qualification to make v.in.ogr happy
1642-
// and remove unnecessary key
1643-
QgsDataSourceUri dataProviderUri( mDataProvider->dataSourceUri() );
1644-
if ( dataProviderUri.hasParam( checkUnicityKey ) )
1645-
dataProviderUri.removeParam( checkUnicityKey );
1646-
mDataSource = dataProviderUri.uri( false );
16471623
}
16481624
else if ( mProviderKey == QLatin1String( "osm" ) )
16491625
{

src/providers/postgres/qgspgtablemodel.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "qgslogger.h"
2121
#include "qgsapplication.h"
2222
#include "qgssettings.h"
23+
#include "qgsproject.h"
2324

2425
#include <climits>
2526

@@ -39,7 +40,7 @@ QgsPgTableModel::QgsPgTableModel()
3940
headerLabels << tr( "Sql" );
4041
setHorizontalHeaderLabels( headerLabels );
4142
setHeaderData( 8, Qt::Orientation::Horizontal, tr( "Disable 'Fast Access to Features at ID' capability to force keeping the attribute table in memory (e.g. in case of expensive views)." ), Qt::ToolTipRole );
42-
setHeaderData( 9, Qt::Orientation::Horizontal, tr( "Enable check for primary key unicity when loading the features. This may slow down loading for large tables." ), Qt::ToolTipRole );
43+
setHeaderData( 9, Qt::Orientation::Horizontal, tr( "Enable check for primary key unicity when loading views and materialized views. This option can make loading of large datasets significantly slower." ), Qt::ToolTipRole );
4344
}
4445

4546
void QgsPgTableModel::addTableEntry( const QgsPostgresLayerProperty &layerProperty )
@@ -127,8 +128,21 @@ void QgsPgTableModel::addTableEntry( const QgsPostgresLayerProperty &layerProper
127128

128129
QStandardItem *checkPkUnicityItem = new QStandardItem( QString() );
129130
checkPkUnicityItem->setFlags( checkPkUnicityItem->flags() | Qt::ItemIsUserCheckable );
130-
checkPkUnicityItem->setCheckState( Qt::Unchecked );
131-
checkPkUnicityItem->setToolTip( headerData( 9, Qt::Orientation::Horizontal, Qt::ToolTipRole ).toString() );
131+
132+
// Legacy: default value is determined by project option to trust layer's metadata
133+
// TODO: remove this default from QGIS 4 and leave default value to false
134+
// checkPkUnicity has only effect on views and materialized views, so we can safely disable it
135+
if ( layerProperty.isView || layerProperty.isMaterializedView )
136+
{
137+
checkPkUnicityItem->setCheckState( QgsProject::instance( )->trustLayerMetadata() ? Qt::CheckState::Unchecked : Qt::CheckState::Checked );
138+
checkPkUnicityItem->setToolTip( headerData( 9, Qt::Orientation::Horizontal, Qt::ToolTipRole ).toString() );
139+
}
140+
else
141+
{
142+
checkPkUnicityItem->setCheckState( Qt::CheckState::Unchecked );
143+
checkPkUnicityItem->setFlags( checkPkUnicityItem->flags() & ~ Qt::ItemIsEnabled );
144+
checkPkUnicityItem->setToolTip( tr( "This option is only available for views and materialized views." ) );
145+
}
132146

133147
QStandardItem *sqlItem = new QStandardItem( layerProperty.sql );
134148

@@ -383,7 +397,7 @@ QString QgsPgTableModel::layerURI( const QModelIndex &index, const QString &conn
383397

384398
bool selectAtId = itemFromIndex( index.sibling( index.row(), DbtmSelectAtId ) )->checkState() == Qt::Checked;
385399
QString sql = index.sibling( index.row(), DbtmSql ).data( Qt::DisplayRole ).toString();
386-
bool checkPkUnicity = itemFromIndex( index.sibling( index.row(), DbtmCheckPkUnicity ) )->checkState() == Qt::Checked;
400+
bool checkPrimaryKeyUnicity = itemFromIndex( index.sibling( index.row(), DbtmCheckPkUnicity ) )->checkState() == Qt::Checked;
387401

388402
QgsDataSourceUri uri( connInfo );
389403

@@ -400,7 +414,7 @@ QString QgsPgTableModel::layerURI( const QModelIndex &index, const QString &conn
400414
uri.setWkbType( wkbType );
401415
uri.setSrid( srid );
402416
uri.disableSelectAtId( !selectAtId );
403-
uri.setParam( QStringLiteral( "checkPrimaryKeyUnicity" ), QString( checkPkUnicity ) );
417+
uri.setParam( QStringLiteral( "checkPrimaryKeyUnicity" ), checkPrimaryKeyUnicity ? QLatin1Literal( "1" ) : QLatin1Literal( "0" ) );
404418

405419
QgsDebugMsg( QStringLiteral( "returning uri %1" ).arg( uri.uri( false ) ) );
406420
return uri.uri( false );

src/providers/postgres/qgspostgresconn.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ struct QgsPostgresLayerProperty
8282
bool isView = false;
8383
bool isMaterializedView = false;
8484
QString tableComment;
85-
bool checkPkUnicity = false;
86-
8785

8886
// TODO: rename this !
8987
int size() const { Q_ASSERT( types.size() == srids.size() ); return types.size(); }

src/providers/postgres/qgspostgresprovider.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,7 +1312,7 @@ bool QgsPostgresProvider::determinePrimaryKey()
13121312

13131313
QStringList log;
13141314

1315-
// no primary or unique indizes found
1315+
// no primary or unique indices found
13161316
if ( res.PQntuples() == 0 )
13171317
{
13181318
QgsDebugMsg( QStringLiteral( "Relation has no primary key -- investigating alternatives" ) );
@@ -1568,7 +1568,6 @@ bool QgsPostgresProvider::uniqueData( const QString &quotedColNames )
15681568
pushError( unique.PQresultErrorMessage() );
15691569
return false;
15701570
}
1571-
15721571
return unique.PQntuples() == 1 && unique.PQgetvalue( 0, 0 ).startsWith( 't' );
15731572
}
15741573

src/ui/qgsprojectpropertiesbase.ui

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@
236236
</sizepolicy>
237237
</property>
238238
<property name="currentIndex">
239-
<number>8</number>
239+
<number>4</number>
240240
</property>
241241
<widget class="QWidget" name="mProjOptsGeneral">
242242
<layout class="QVBoxLayout" name="verticalLayout_6">
@@ -265,8 +265,8 @@
265265
<rect>
266266
<x>0</x>
267267
<y>0</y>
268-
<width>590</width>
269-
<height>777</height>
268+
<width>671</width>
269+
<height>795</height>
270270
</rect>
271271
</property>
272272
<layout class="QVBoxLayout" name="verticalLayout_8">
@@ -863,8 +863,8 @@
863863
<rect>
864864
<x>0</x>
865865
<y>0</y>
866-
<width>603</width>
867-
<height>161</height>
866+
<width>685</width>
867+
<height>780</height>
868868
</rect>
869869
</property>
870870
<layout class="QVBoxLayout" name="verticalLayout_7">
@@ -938,8 +938,8 @@
938938
<rect>
939939
<x>0</x>
940940
<y>0</y>
941-
<width>290</width>
942-
<height>543</height>
941+
<width>685</width>
942+
<height>780</height>
943943
</rect>
944944
</property>
945945
<layout class="QVBoxLayout" name="verticalLayout_12">
@@ -1378,7 +1378,7 @@
13781378
<item row="3" column="0">
13791379
<widget class="QCheckBox" name="mTrustProjectCheckBox">
13801380
<property name="toolTip">
1381-
<string>Speed up project loading by skipping data checks. Useful in qgis server context or project with huge database views or materialized views.</string>
1381+
<string>Speed up project loading by skipping data checks in Postgres layers. Useful in QGIS server context or project with huge database views or materialized views.</string>
13821382
</property>
13831383
<property name="text">
13841384
<string>Trust project when data source has no metadata</string>
@@ -1514,8 +1514,8 @@
15141514
<rect>
15151515
<x>0</x>
15161516
<y>0</y>
1517-
<width>178</width>
1518-
<height>54</height>
1517+
<width>167</width>
1518+
<height>55</height>
15191519
</rect>
15201520
</property>
15211521
<layout class="QVBoxLayout" name="verticalLayout_17">
@@ -1575,9 +1575,9 @@
15751575
<property name="geometry">
15761576
<rect>
15771577
<x>0</x>
1578-
<y>-975</y>
1578+
<y>0</y>
15791579
<width>671</width>
1580-
<height>2682</height>
1580+
<height>2732</height>
15811581
</rect>
15821582
</property>
15831583
<layout class="QVBoxLayout" name="verticalLayout_13">

tests/src/python/test_provider_postgres.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,21 @@ def testReadExtentOnTable(self):
10971097

10981098
self.assertEqual(vl2.extent(), originalExtent)
10991099

1100+
def testCheckPkUnicityOnView(self):
1101+
# vector layer based on view
1102+
1103+
# This is valid
1104+
vl0 = QgsVectorLayer(self.dbconn + ' checkPrimaryKeyUnicity=\'0\' sslmode=disable key=\'pk\' srid=0 type=POINT table="qgis_test"."b21839_pk_unicity_view" (geom) sql=', 'test', 'postgres')
1105+
self.assertTrue(vl0.isValid())
1106+
1107+
# This is NOT valid
1108+
vl0 = QgsVectorLayer(self.dbconn + ' checkPrimaryKeyUnicity=\'1\' sslmode=disable key=\'an_int\' srid=0 type=POINT table="qgis_test"."b21839_pk_unicity_view" (geom) sql=', 'test', 'postgres')
1109+
self.assertFalse(vl0.isValid())
1110+
1111+
# This is valid because the default is to not check unicity
1112+
vl0 = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'an_int\' srid=0 type=POINT table="qgis_test"."b21839_pk_unicity_view" (geom) sql=', 'test', 'postgres')
1113+
self.assertFalse(vl0.isValid())
1114+
11001115
def testNotify(self):
11011116
vl0 = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', 'test', 'postgres')
11021117
vl0.dataProvider().setListening(True)

tests/testdata/provider/testdata_pg.sql

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,3 +535,41 @@ INSERT INTO qgis_test.check_constraints VALUES (
535535
4, -- a
536536
3 -- b
537537
)
538+
539+
540+
---------------------------------------------
541+
--
542+
-- Table and view for tests on checkPrimaryKeyUnicity
543+
--
544+
545+
546+
DROP TABLE IF EXISTS qgis_test.b21839_pk_unicity CASCADE;
547+
CREATE TABLE qgis_test.b21839_pk_unicity
548+
(
549+
pk serial NOT NULL,
550+
an_int integer NOT NULL,
551+
geom geometry(Point),
552+
CONSTRAINT b21839_pk_unicity_pkey PRIMARY KEY (pk)
553+
)
554+
WITH (
555+
OIDS=FALSE
556+
);
557+
558+
559+
INSERT INTO qgis_test.b21839_pk_unicity(
560+
pk, an_int, geom)
561+
VALUES (1, 1, ST_GeomFromText('point( 1 1)'));
562+
563+
564+
INSERT INTO qgis_test.b21839_pk_unicity(
565+
pk, an_int, geom)
566+
VALUES (2, 1, ST_GeomFromText('point( 1 3)'));
567+
568+
569+
570+
CREATE OR REPLACE VIEW qgis_test.b21839_pk_unicity_view AS
571+
SELECT b21839_pk_unicity.pk,
572+
b21839_pk_unicity.an_int,
573+
b21839_pk_unicity.geom
574+
FROM qgis_test.b21839_pk_unicity;
575+

0 commit comments

Comments
 (0)