Skip to content

Commit b0bd61f

Browse files
committed
[FEATURE] Detect default literal values from OGR layers
Requires GDAL >= 2
1 parent 0ae610c commit b0bd61f

File tree

3 files changed

+87
-1
lines changed

3 files changed

+87
-1
lines changed

src/providers/ogr/qgsogrprovider.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,7 @@ void QgsOgrProvider::loadFields()
840840
QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() );
841841
//the attribute fields need to be read again when the encoding changes
842842
mAttributeFields.clear();
843+
mDefaultValues.clear();
843844
if ( !ogrLayer )
844845
return;
845846

@@ -947,6 +948,13 @@ void QgsOgrProvider::loadFields()
947948
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
948949
newField.setConstraints( constraints );
949950
}
951+
952+
// check if field has default value
953+
QString defaultValue = textEncoding()->toUnicode( OGR_Fld_GetDefault( fldDef ) );
954+
if ( !defaultValue.isEmpty() && !OGR_Fld_IsDefaultDriverSpecific( fldDef ) )
955+
{
956+
mDefaultValues.insert( i + ( mFirstFieldIsFid ? 1 : 0 ), defaultValue );
957+
}
950958
#endif
951959

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

1092+
QVariant QgsOgrProvider::defaultValue( int fieldId ) const
1093+
{
1094+
if ( fieldId < 0 || fieldId >= mAttributeFields.count() )
1095+
return QVariant();
1096+
1097+
QString defaultVal = mDefaultValues.value( fieldId, QString() );
1098+
if ( defaultVal.isEmpty() )
1099+
return QVariant();
1100+
1101+
QVariant resultVar = defaultVal;
1102+
if ( defaultVal == QStringLiteral( "CURRENT_TIMESTAMP" ) )
1103+
resultVar = QDateTime::currentDateTime();
1104+
else if ( defaultVal == QStringLiteral( "CURRENT_DATE" ) )
1105+
resultVar = QDate::currentDate();
1106+
else if ( defaultVal == QStringLiteral( "CURRENT_TIME" ) )
1107+
resultVar = QTime::currentTime();
1108+
else if ( defaultVal.startsWith( '\'' ) )
1109+
{
1110+
defaultVal = defaultVal.remove( 0, 1 );
1111+
defaultVal.chop( 1 );
1112+
defaultVal.replace( "''", "'" );
1113+
resultVar = defaultVal;
1114+
}
1115+
1116+
( void )mAttributeFields.at( fieldId ).convertCompatible( resultVar );
1117+
return resultVar;
1118+
}
1119+
10841120
void QgsOgrProvider::updateExtents()
10851121
{
10861122
invalidateCachedExtent( true );

src/providers/ogr/qgsogrprovider.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ class QgsOgrProvider : public QgsVectorDataProvider
124124

125125
virtual QgsRectangle extent() const override;
126126

127+
QVariant defaultValue( int fieldId ) const override;
128+
127129
/** Update the extents
128130
*/
129131
virtual void updateExtents() override;
@@ -297,7 +299,12 @@ class QgsOgrProvider : public QgsVectorDataProvider
297299
private:
298300
unsigned char *getGeometryPointer( OGRFeatureH fet );
299301
QString ogrWkbGeometryTypeName( OGRwkbGeometryType type ) const;
302+
300303
QgsFields mAttributeFields;
304+
305+
//! Map of field index to default value
306+
QMap<int, QString> mDefaultValues;
307+
301308
bool mFirstFieldIsFid;
302309
OGRDataSourceH ogrDataSource;
303310
mutable OGREnvelope* mExtent;

tests/src/python/test_provider_ogr_sqlite.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
import glob
2121
from osgeo import gdal, ogr
2222

23-
from qgis.core import QgsVectorLayer, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsField, QgsFieldConstraints
23+
from qgis.core import QgsVectorLayer, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsField, QgsFieldConstraints, NULL
2424
from qgis.testing import start_app, unittest
2525
from utilities import unitTestDataPath
26+
from qgis.PyQt.QtCore import QDate, QTime, QDateTime
2627

2728
start_app()
2829

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

164+
@unittest.expectedFailure(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 0, 0))
165+
def testDefaultValues(self):
166+
""" test detection of defaults on OGR layer """
167+
168+
tmpfile = os.path.join(self.basetestpath, 'testDefaults.sqlite')
169+
ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
170+
lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
171+
lyr.CreateField(ogr.FieldDefn('field1', ogr.OFTInteger))
172+
fld2 = ogr.FieldDefn('field2', ogr.OFTInteger)
173+
fld2.SetDefault('5')
174+
lyr.CreateField(fld2)
175+
fld3 = ogr.FieldDefn('field3', ogr.OFTString)
176+
fld3.SetDefault("'some ''default'")
177+
lyr.CreateField(fld3)
178+
fld4 = ogr.FieldDefn('field4', ogr.OFTDate)
179+
fld4.SetDefault("CURRENT_DATE")
180+
lyr.CreateField(fld4)
181+
fld5 = ogr.FieldDefn('field5', ogr.OFTTime)
182+
fld5.SetDefault("CURRENT_TIME")
183+
lyr.CreateField(fld5)
184+
fld6 = ogr.FieldDefn('field6', ogr.OFTDateTime)
185+
fld6.SetDefault("CURRENT_TIMESTAMP")
186+
lyr.CreateField(fld6)
187+
188+
ds = None
189+
190+
vl = QgsVectorLayer('{}'.format(tmpfile), 'test', 'ogr')
191+
self.assertTrue(vl.isValid())
192+
193+
# test some bad indexes
194+
self.assertFalse(vl.dataProvider().defaultValue(-1))
195+
self.assertFalse(vl.dataProvider().defaultValue(1001))
196+
197+
# test default
198+
self.assertEqual(vl.dataProvider().defaultValue(1), NULL)
199+
self.assertEqual(vl.dataProvider().defaultValue(2), 5)
200+
self.assertEqual(vl.dataProvider().defaultValue(3), "some 'default")
201+
self.assertEqual(vl.dataProvider().defaultValue(4), QDate.currentDate())
202+
# time may pass, so we allow 1 second difference here
203+
self.assertTrue(vl.dataProvider().defaultValue(5).secsTo(QTime.currentTime()) < 1)
204+
self.assertTrue(vl.dataProvider().defaultValue(6).secsTo(QDateTime.currentDateTime()) < 1)
205+
163206

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

0 commit comments

Comments
 (0)