Skip to content
Permalink
Browse files

[FEATURE] Detect default literal values from OGR layers

Requires GDAL >= 2
  • Loading branch information
nyalldawson committed Nov 7, 2016
1 parent 0ae610c commit b0bd61f308333381b832d8b7961dfd714e76338f
@@ -840,6 +840,7 @@ void QgsOgrProvider::loadFields()
QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() );
//the attribute fields need to be read again when the encoding changes
mAttributeFields.clear();
mDefaultValues.clear();
if ( !ogrLayer )
return;

@@ -947,6 +948,13 @@ void QgsOgrProvider::loadFields()
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
newField.setConstraints( constraints );
}

// check if field has default value
QString defaultValue = textEncoding()->toUnicode( OGR_Fld_GetDefault( fldDef ) );
if ( !defaultValue.isEmpty() && !OGR_Fld_IsDefaultDriverSpecific( fldDef ) )
{
mDefaultValues.insert( i + ( mFirstFieldIsFid ? 1 : 0 ), defaultValue );
}
#endif

mAttributeFields.append( newField );
@@ -1081,6 +1089,34 @@ QgsRectangle QgsOgrProvider::extent() const
return mExtentRect;
}

QVariant QgsOgrProvider::defaultValue( int fieldId ) const
{
if ( fieldId < 0 || fieldId >= mAttributeFields.count() )
return QVariant();

QString defaultVal = mDefaultValues.value( fieldId, QString() );
if ( defaultVal.isEmpty() )
return QVariant();

QVariant resultVar = defaultVal;
if ( defaultVal == QStringLiteral( "CURRENT_TIMESTAMP" ) )
resultVar = QDateTime::currentDateTime();
else if ( defaultVal == QStringLiteral( "CURRENT_DATE" ) )
resultVar = QDate::currentDate();
else if ( defaultVal == QStringLiteral( "CURRENT_TIME" ) )
resultVar = QTime::currentTime();
else if ( defaultVal.startsWith( '\'' ) )
{
defaultVal = defaultVal.remove( 0, 1 );
defaultVal.chop( 1 );
defaultVal.replace( "''", "'" );
resultVar = defaultVal;
}

( void )mAttributeFields.at( fieldId ).convertCompatible( resultVar );
return resultVar;
}

void QgsOgrProvider::updateExtents()
{
invalidateCachedExtent( true );
@@ -124,6 +124,8 @@ class QgsOgrProvider : public QgsVectorDataProvider

virtual QgsRectangle extent() const override;

QVariant defaultValue( int fieldId ) const override;

/** Update the extents
*/
virtual void updateExtents() override;
@@ -297,7 +299,12 @@ class QgsOgrProvider : public QgsVectorDataProvider
private:
unsigned char *getGeometryPointer( OGRFeatureH fet );
QString ogrWkbGeometryTypeName( OGRwkbGeometryType type ) const;

QgsFields mAttributeFields;

//! Map of field index to default value
QMap<int, QString> mDefaultValues;

bool mFirstFieldIsFid;
OGRDataSourceH ogrDataSource;
mutable OGREnvelope* mExtent;
@@ -20,9 +20,10 @@
import glob
from osgeo import gdal, ogr

from qgis.core import QgsVectorLayer, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsField, QgsFieldConstraints
from qgis.core import QgsVectorLayer, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsField, QgsFieldConstraints, NULL
from qgis.testing import start_app, unittest
from utilities import unitTestDataPath
from qgis.PyQt.QtCore import QDate, QTime, QDateTime

start_app()

@@ -160,6 +161,48 @@ def testNotNullConstraint(self):
self.assertTrue(fields.at(2).constraints().constraints() & QgsFieldConstraints.ConstraintNotNull)
self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.ConstraintNotNull), QgsFieldConstraints.ConstraintOriginProvider)

@unittest.expectedFailure(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 0, 0))
def testDefaultValues(self):
""" test detection of defaults on OGR layer """

tmpfile = os.path.join(self.basetestpath, 'testDefaults.sqlite')
ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
lyr.CreateField(ogr.FieldDefn('field1', ogr.OFTInteger))
fld2 = ogr.FieldDefn('field2', ogr.OFTInteger)
fld2.SetDefault('5')
lyr.CreateField(fld2)
fld3 = ogr.FieldDefn('field3', ogr.OFTString)
fld3.SetDefault("'some ''default'")
lyr.CreateField(fld3)
fld4 = ogr.FieldDefn('field4', ogr.OFTDate)
fld4.SetDefault("CURRENT_DATE")
lyr.CreateField(fld4)
fld5 = ogr.FieldDefn('field5', ogr.OFTTime)
fld5.SetDefault("CURRENT_TIME")
lyr.CreateField(fld5)
fld6 = ogr.FieldDefn('field6', ogr.OFTDateTime)
fld6.SetDefault("CURRENT_TIMESTAMP")
lyr.CreateField(fld6)

ds = None

vl = QgsVectorLayer('{}'.format(tmpfile), 'test', 'ogr')
self.assertTrue(vl.isValid())

# test some bad indexes
self.assertFalse(vl.dataProvider().defaultValue(-1))
self.assertFalse(vl.dataProvider().defaultValue(1001))

# test default
self.assertEqual(vl.dataProvider().defaultValue(1), NULL)
self.assertEqual(vl.dataProvider().defaultValue(2), 5)
self.assertEqual(vl.dataProvider().defaultValue(3), "some 'default")
self.assertEqual(vl.dataProvider().defaultValue(4), QDate.currentDate())
# time may pass, so we allow 1 second difference here
self.assertTrue(vl.dataProvider().defaultValue(5).secsTo(QTime.currentTime()) < 1)
self.assertTrue(vl.dataProvider().defaultValue(6).secsTo(QDateTime.currentDateTime()) < 1)


if __name__ == '__main__':
unittest.main()

0 comments on commit b0bd61f

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