Skip to content

Commit

Permalink
Make sure primary keys are always marked with a unique, not null
Browse files Browse the repository at this point in the history
constraint for all providers
  • Loading branch information
nyalldawson authored and m-kuhn committed Nov 16, 2016
1 parent b5864cd commit 091f488
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 101 deletions.
7 changes: 7 additions & 0 deletions src/providers/arcgisrest/qgsafsprovider.cpp
Expand Up @@ -132,6 +132,13 @@ QgsAfsProvider::QgsAfsProvider( const QString& uri )
if ( mFields.at( idx ).name() == mObjectIdFieldName )
{
mObjectIdFieldIdx = idx;

// primary key is not null, unique
QgsFieldConstraints constraints = mFields.at( idx ).constraints();
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginProvider );
mFields[ idx ].setConstraints( constraints );

break;
}
}
Expand Down
24 changes: 23 additions & 1 deletion src/providers/db2/qgsdb2provider.cpp
Expand Up @@ -33,6 +33,7 @@ int QgsDb2Provider::sConnectionId = 0;
QgsDb2Provider::QgsDb2Provider( const QString& uri )
: QgsVectorDataProvider( uri )
, mNumberFeatures( 0 )
, mFidColIdx( -1 )
, mEnvironment( ENV_LUW )
, mWkbType( QgsWkbTypes::Unknown )
{
Expand Down Expand Up @@ -330,12 +331,25 @@ void QgsDb2Provider::loadFields()
}
// Hack to get primary key since the primaryIndex function above doesn't work
// on z/OS. Pick first integer column.
if ( mFidColName.length() == 0 &&
if ( mFidColName.isEmpty() &&
( sqlType == QVariant::LongLong || sqlType == QVariant::Int ) )
{
mFidColName = f.name();
}
}

if ( !mFidColName.isEmpty() )
{
mFidColIdx = mAttributeFields.indexFromName( mFidColName );
if ( mFidColIdx >= 0 )
{
// primary key has not null, unique constraints
QgsFieldConstraints constraints = mAttributeFields.at( mFidColIdx ).constraints();
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginProvider );
mAttributeFields[ mFidColIdx ].setConstraints( constraints );
}
}
}

QVariant::Type QgsDb2Provider::decodeSqlType( int typeId )
Expand Down Expand Up @@ -1664,6 +1678,14 @@ QString QgsDb2Provider::description() const
return PROVIDER_DESCRIPTION;
}

QgsAttributeList QgsDb2Provider::pkAttributeIndexes() const
{
QgsAttributeList list;
if ( mFidColIdx >= 0 )
list << mFidColIdx;
return list;
}

QGISEXTERN QgsDb2Provider *classFactory( const QString *uri )
{
return new QgsDb2Provider( *uri );
Expand Down
34 changes: 3 additions & 31 deletions src/providers/db2/qgsdb2provider.h
Expand Up @@ -54,16 +54,8 @@ class QgsDb2Provider : public QgsVectorDataProvider

virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request = QgsFeatureRequest() ) const override;

/**
* Get feature type.
* @return int representing the feature type
*/
virtual QgsWkbTypes::Type wkbType() const override;

/**
* Number of features in the layer
* @return long containing number of features
*/
virtual long featureCount() const override;

/**
Expand All @@ -79,45 +71,24 @@ class QgsDb2Provider : public QgsVectorDataProvider
virtual bool isValid() const override;
QString subsetString() const override;

/**
* Mutator for SQL WHERE clause used to limit dataset size.
*/
bool setSubsetString( const QString& theSQL, bool updateFeatureCount = true ) override;

virtual bool supportsSubsetString() const override { return true; }

/** Return a provider name
Essentially just returns the provider key. Should be used to build file
dialogs so that providers can be shown with their supported types. Thus
if more than one provider supports a given format, the user is able to
select a specific provider to open that file.
*/
virtual QString name() const override;

/** Return description
Return a terse string describing what the provider is.
*/
virtual QString description() const override;

/** Returns a bitmask containing the supported capabilities
Note, some capabilities may change depending on whether
a spatial filter is active on this provider, so it may
be prudent to check this value per intended operation.
*/
QgsAttributeList pkAttributeIndexes() const override;

virtual QgsVectorDataProvider::Capabilities capabilities() const override;

//! Writes a list of features to the database
virtual bool addFeatures( QgsFeatureList & flist ) override;

//! Deletes a feature
virtual bool deleteFeatures( const QgsFeatureIds & id ) override;

//! Changes attribute values of existing features
virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;

//! Changes existing geometries
virtual bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;

//! Import a vector layer into the database
Expand Down Expand Up @@ -155,6 +126,7 @@ class QgsDb2Provider : public QgsVectorDataProvider
bool mUseEstimatedMetadata;
bool mSkipFailures;
long mNumberFeatures;
int mFidColIdx;
QString mFidColName;
QString mExtents;
mutable long mSRId;
Expand Down
24 changes: 23 additions & 1 deletion src/providers/mssql/qgsmssqlprovider.cpp
Expand Up @@ -56,6 +56,7 @@ int QgsMssqlProvider::sConnectionId = 0;
QgsMssqlProvider::QgsMssqlProvider( const QString& uri )
: QgsVectorDataProvider( uri )
, mNumberFeatures( 0 )
, mFidColIdx( -1 )
, mCrs()
, mWkbType( QgsWkbTypes::Unknown )
{
Expand Down Expand Up @@ -472,6 +473,19 @@ void QgsMssqlProvider::loadFields()
mValid = false;
setLastError( error );
}

if ( !mFidColName.isEmpty() )
{
mFidColIdx = mAttributeFields.indexFromName( mFidColName );
if ( mFidColIdx >= 0 )
{
// primary key has not null, unique constraints
QgsFieldConstraints constraints = mAttributeFields.at( mFidColIdx ).constraints();
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginProvider );
mAttributeFields[ mFidColIdx ].setConstraints( constraints );
}
}
}
}

Expand Down Expand Up @@ -1481,7 +1495,15 @@ bool QgsMssqlProvider::setSubsetString( const QString& theSQL, bool )
QString QgsMssqlProvider::description() const
{
return TEXT_PROVIDER_DESCRIPTION;
} // QgsMssqlProvider::name()
}

QgsAttributeList QgsMssqlProvider::pkAttributeIndexes() const
{
QgsAttributeList list;
if ( mFidColIdx >= 0 )
list << mFidColIdx;
return list;
}

QStringList QgsMssqlProvider::subLayers() const
{
Expand Down
68 changes: 3 additions & 65 deletions src/providers/mssql/qgsmssqlprovider.h
Expand Up @@ -62,33 +62,15 @@ class QgsMssqlProvider : public QgsVectorDataProvider

/* Implementation of functions from QgsVectorDataProvider */

/**
* Returns the permanent storage type for this layer as a friendly name.
*/
virtual QString storageType() const override;

/**
* Sub-layers handled by this provider, in order from bottom to top
*
* Sub-layers are used when the provider's source can combine layers
* it knows about in some way before it hands them off to the provider.
*/
virtual QStringList subLayers() const override;
virtual QVariant minimumValue( int index ) const override;
virtual QVariant maximumValue( int index ) const override;
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request ) const override;

/**
* Get feature type.
* @return int representing the feature type
*/
virtual QgsWkbTypes::Type wkbType() const override;

/**
* Number of features in the layer
* @return long containing number of features
*/
virtual long featureCount() const override;

//! Update the extent, feature count, wkb type and srid for this layer
Expand All @@ -98,86 +80,41 @@ class QgsMssqlProvider : public QgsVectorDataProvider

QString subsetString() const override;

//! Mutator for sql where clause used to limit dataset size
bool setSubsetString( const QString& theSQL, bool updateFeatureCount = true ) override;

virtual bool supportsSubsetString() const override { return true; }

/** Returns a bitmask containing the supported capabilities
Note, some capabilities may change depending on whether
a spatial filter is active on this provider, so it may
be prudent to check this value per intended operation.
*/
virtual QgsVectorDataProvider::Capabilities capabilities() const override;


/* Implementation of functions from QgsDataProvider */

/** Return a provider name
Essentially just returns the provider key. Should be used to build file
dialogs so that providers can be shown with their supported types. Thus
if more than one provider supports a given format, the user is able to
select a specific provider to open that file.
@note
Instead of being pure virtual, might be better to generalize this
behavior and presume that none of the sub-classes are going to do
anything strange with regards to their name or description?
*/
QString name() const override;

/** Return description
Return a terse string describing what the provider is.
@note
Instead of being pure virtual, might be better to generalize this
behavior and presume that none of the sub-classes are going to do
anything strange with regards to their name or description?
*/
QString description() const override;

QgsAttributeList pkAttributeIndexes() const override;

virtual QgsRectangle extent() const override;

bool isValid() const override;

virtual bool isSaveAndLoadStyleToDBSupported() const override { return true; }

//! Writes a list of features to the database
virtual bool addFeatures( QgsFeatureList & flist ) override;

//! Deletes a feature
virtual bool deleteFeatures( const QgsFeatureIds & id ) override;

/**
* Adds new attributes
* @param attributes list of new attributes
* @return true in case of success and false in case of failure
*/
virtual bool addAttributes( const QList<QgsField> &attributes ) override;

/**
* Deletes existing attributes
* @param attributes a set containing names of attributes
* @return true in case of success and false in case of failure
*/
virtual bool deleteAttributes( const QgsAttributeIds &attributes ) override;

//! Changes attribute values of existing features
virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;

//! Changes existing geometries
virtual bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;

/**
* Create a spatial index for the current layer
*/
virtual bool createSpatialIndex() override;

//! Create an attribute index on the datasource
virtual bool createAttributeIndex( int field ) override;

//! Convert a QgsField to work with MSSQL
Expand Down Expand Up @@ -227,6 +164,7 @@ class QgsMssqlProvider : public QgsVectorDataProvider

long mNumberFeatures;
QString mFidColName;
int mFidColIdx;
mutable long mSRId;
QString mGeometryColName;
QString mGeometryColType;
Expand Down
20 changes: 19 additions & 1 deletion src/providers/oracle/qgsoracleprovider.cpp
Expand Up @@ -752,7 +752,16 @@ bool QgsOracleProvider::loadFields()
type = QVariant::Date;
}

mAttributeFields.append( QgsField( field.name(), type, types.value( field.name() ), field.length(), field.precision(), comments.value( field.name() ) ) );
QgsField newField( field.name(), type, types.value( field.name() ), field.length(), field.precision(), comments.value( field.name() ) );

QgsFieldConstraints constraints;
if ( mPrimaryKeyAttrs.contains( i ) )
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
if ( mPrimaryKeyAttrs.contains( i ) )
constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginProvider );
newField.setConstraints( constraints );

mAttributeFields.append( newField );
mDefaultValues.append( defvalues.value( field.name(), QVariant() ) );
}

Expand Down Expand Up @@ -987,6 +996,15 @@ bool QgsOracleProvider::determinePrimaryKey()

mValid = mPrimaryKeyType != pktUnknown;

Q_FOREACH ( int fieldIdx, mPrimaryKeyAttrs )
{
//primary keys are unique, not null
QgsFieldConstraints constraints = mAttributeFields.at( fieldIdx ).constraints();
constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginProvider );
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
mAttributeFields[ fieldIdx ].setConstraints( constraints );
}

return mValid;
}

Expand Down
13 changes: 11 additions & 2 deletions src/providers/postgres/qgspostgresprovider.cpp
Expand Up @@ -1002,9 +1002,9 @@ bool QgsPostgresProvider::loadFields()
QgsField newField = QgsField( fieldName, fieldType, fieldTypeName, fieldSize, fieldPrec, fieldComment, fieldSubType );

QgsFieldConstraints constraints;
if ( notNullMap[tableoid][attnum] )
if ( notNullMap[tableoid][attnum] || mPrimaryKeyAttrs.contains( i ) )
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
if ( uniqueMap[tableoid][attnum] )
if ( uniqueMap[tableoid][attnum] || mPrimaryKeyAttrs.contains( i ) )
constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginProvider );
newField.setConstraints( constraints );

Expand Down Expand Up @@ -1375,6 +1375,15 @@ bool QgsPostgresProvider::determinePrimaryKey()
determinePrimaryKeyFromUriKeyColumn();
}

Q_FOREACH ( int fieldIdx, mPrimaryKeyAttrs )
{
//primary keys are unique, not null
QgsFieldConstraints constraints = mAttributeFields.at( fieldIdx ).constraints();
constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginProvider );
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
mAttributeFields[ fieldIdx ].setConstraints( constraints );
}

mValid = mPrimaryKeyType != pktUnknown;

return mValid;
Expand Down

0 comments on commit 091f488

Please sign in to comment.