Skip to content
Permalink
Browse files

Make sure primary keys are always marked with a unique, not null

constraint for all providers
  • Loading branch information
nyalldawson authored and m-kuhn committed Nov 16, 2016
1 parent b5864cd commit 091f4889858b0e09e52d7a8c1e7a86ce803eb9f1
@@ -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;
}
}
@@ -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 )
{
@@ -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 )
@@ -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 );
@@ -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;

/**
@@ -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
@@ -155,6 +126,7 @@ class QgsDb2Provider : public QgsVectorDataProvider
bool mUseEstimatedMetadata;
bool mSkipFailures;
long mNumberFeatures;
int mFidColIdx;
QString mFidColName;
QString mExtents;
mutable long mSRId;
@@ -56,6 +56,7 @@ int QgsMssqlProvider::sConnectionId = 0;
QgsMssqlProvider::QgsMssqlProvider( const QString& uri )
: QgsVectorDataProvider( uri )
, mNumberFeatures( 0 )
, mFidColIdx( -1 )
, mCrs()
, mWkbType( QgsWkbTypes::Unknown )
{
@@ -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 );
}
}
}
}

@@ -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
{
@@ -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
@@ -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
@@ -227,6 +164,7 @@ class QgsMssqlProvider : public QgsVectorDataProvider

long mNumberFeatures;
QString mFidColName;
int mFidColIdx;
mutable long mSRId;
QString mGeometryColName;
QString mGeometryColType;
@@ -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() ) );
}

@@ -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;
}

@@ -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 );

@@ -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;

0 comments on commit 091f488

Please sign in to comment.
You can’t perform that action at this time.