diff --git a/src/providers/postgres/qgspostgresprovider.cpp b/src/providers/postgres/qgspostgresprovider.cpp index c8d8658ff43..18eae093a3d 100644 --- a/src/providers/postgres/qgspostgresprovider.cpp +++ b/src/providers/postgres/qgspostgresprovider.cpp @@ -52,6 +52,26 @@ inline int32_t FID2PKINT( int64_t x ) return QgsPostgresUtils::fid_to_int32pk( x ); } +QgsPostgresPrimaryKeyType +QgsPostgresProvider::pkType( const QgsField& f ) const +{ + switch ( f.type() ) + { + case QVariant::LongLong: + // unless we can guarantee all values are unsigned + // (in which case we could use pktUint64) + // we'll have to use a Map type. + // See http://hub.qgis.org/issues/14262 + return pktFidMap; // pktUint64 + + case QVariant::Int: + return pktInt; + + default: + return pktFidMap; + } +} + QgsPostgresProvider::QgsPostgresProvider( QString const & uri ) @@ -1312,7 +1332,7 @@ bool QgsPostgresProvider::determinePrimaryKey() QString primaryKey; QString delim = ""; - mPrimaryKeyType = pktFidMap; // int by default, will downgrade if needed + mPrimaryKeyType = pktFidMap; // map by default, will downgrade if needed for ( int i = 0; i < res.PQntuples(); i++ ) { QString name = res.PQgetvalue( i, 0 ); @@ -1333,22 +1353,8 @@ bool QgsPostgresProvider::determinePrimaryKey() } const QgsField& fld = mAttributeFields.at( idx ); - if ( i ) - { - mPrimaryKeyType = pktFidMap; // multi-field - } - else if ( fld.type() == QVariant::LongLong ) - { - // unless we can guarantee all values are unsigned - // (in which case we could use pktUint64) - // we'll have to use a Map type. - // See http://hub.qgis.org/issues/14262 - mPrimaryKeyType = pktFidMap; // pktUint64 - } - else if ( fld.type() == QVariant::Int ) - { - mPrimaryKeyType = pktInt; - } + // Always use pktFidMap for multi-field keys + mPrimaryKeyType = i ? pktFidMap : pkType( fld ); mPrimaryKeyAttrs << idx; } @@ -1444,14 +1450,7 @@ void QgsPostgresProvider::determinePrimaryKeyFromUriKeyColumn() if ( mPrimaryKeyAttrs.size() == 1 ) { const QgsField& fld = mAttributeFields.at( 0 ); - if ( fld.type() == QVariant::LongLong ) - { - mPrimaryKeyType = pktUint64; // 64bit integer - } - else if ( fld.type() == QVariant::Int ) - { - mPrimaryKeyType = pktInt; // account for signed - } + mPrimaryKeyType = pkType( fld ); } } else diff --git a/src/providers/postgres/qgspostgresprovider.h b/src/providers/postgres/qgspostgresprovider.h index ca5a5bc1bdb..46592522cdf 100644 --- a/src/providers/postgres/qgspostgresprovider.h +++ b/src/providers/postgres/qgspostgresprovider.h @@ -352,6 +352,17 @@ class QgsPostgresProvider : public QgsVectorDataProvider */ bool parseDomainCheckConstraint( QStringList& enumValues, const QString& attributeName ) const; + /** Return the type of primary key for a PK field + * + * @param fld the field to determine PK type of + * @return the PrimaryKeyType + * + * @note that this only makes sense for single-field primary keys, + * whereas multi-field keys always need the pktFidMap + * primary key type. + */ + QgsPostgresPrimaryKeyType pkType( const QgsField& fld ) const; + QgsFields mAttributeFields; QString mDataComment; diff --git a/tests/src/python/test_provider_postgres.py b/tests/src/python/test_provider_postgres.py index 6b170c0ed58..832c3a466f8 100644 --- a/tests/src/python/test_provider_postgres.py +++ b/tests/src/python/test_provider_postgres.py @@ -171,9 +171,7 @@ class TestPyQgsPostgresProvider(unittest.TestCase, ProviderTestCase): self.assertEqual(count, 1) test_query_attribute(self.dbconn, '(SELECT -1::int4 i, NULL::geometry(Point) g)', 'i', -1, 4294967295) test_query_attribute(self.dbconn, '(SELECT -2::int2 i, NULL::geometry(Point) g)', 'i', -2, 4294967294) - # Unfortunately negative int8 identifiers are still not supported at this moment - # TODO: fix expected fidval to be positive ! - test_query_attribute(self.dbconn, '(SELECT -3::int8 i, NULL::geometry(Point) g)', 'i', -3, -3) + test_query_attribute(self.dbconn, '(SELECT -3::int8 i, NULL::geometry(Point) g)', 'i', -3, 1) def testPktIntInsert(self): vl = QgsVectorLayer('{} table="qgis_test"."{}" key="pk" sql='.format(self.dbconn, 'bikes_view'), "bikes_view", "postgres")