From 0ae610c5e3dd364385c2fd91f901e706a04101f1 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 7 Nov 2016 14:33:44 +1000 Subject: [PATCH] [FEATURE] Detect literal default values for spatialite provider --- .../spatialite/qgsspatialiteprovider.cpp | 46 ++++++++++++++++++- .../spatialite/qgsspatialiteprovider.h | 7 +++ tests/src/python/test_provider_spatialite.py | 14 ++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/providers/spatialite/qgsspatialiteprovider.cpp b/src/providers/spatialite/qgsspatialiteprovider.cpp index dad23c26909..e483b43a8d6 100644 --- a/src/providers/spatialite/qgsspatialiteprovider.cpp +++ b/src/providers/spatialite/qgsspatialiteprovider.cpp @@ -684,6 +684,7 @@ void QgsSpatiaLiteProvider::loadFieldsAbstractInterface( gaiaVectorLayerPtr lyr mAttributeFields.clear(); mPrimaryKey.clear(); // cazzo cazzo cazzo mPrimaryKeyAttrs.clear(); + mDefaultValues.clear(); gaiaLayerAttributeFieldPtr fld = lyr->First; if ( !fld ) @@ -729,6 +730,8 @@ void QgsSpatiaLiteProvider::loadFieldsAbstractInterface( gaiaVectorLayerPtr lyr for ( int i = 1; i <= rows; i++ ) { QString name = QString::fromUtf8( results[( i * columns ) + 1] ); + insertDefaultValue( i - 1, QString::fromUtf8( results[( i * columns ) + 4] ) ); + QString pk = results[( i * columns ) + 5]; QString type = results[( i * columns ) + 2]; type = type.toLower(); @@ -870,6 +873,37 @@ error: } +void QgsSpatiaLiteProvider::insertDefaultValue( int fieldIndex, QString defaultVal ) +{ + if ( !defaultVal.isEmpty() ) + { + QVariant defaultVariant; + switch ( mAttributeFields.at( fieldIndex ).type() ) + { + case QVariant::LongLong: + defaultVariant = defaultVal.toLongLong(); + break; + + case QVariant::Double: + defaultVariant = defaultVal.toDouble(); + break; + + default: + { + if ( defaultVal.startsWith( '\'' ) ) + defaultVal = defaultVal.remove( 0, 1 ); + if ( defaultVal.endsWith( '\'' ) ) + defaultVal.chop( 1 ); + defaultVal.replace( "''", "'" ); + + defaultVariant = defaultVal; + break; + } + } + mDefaultValues.insert( fieldIndex, defaultVariant ); + } +} + void QgsSpatiaLiteProvider::loadFields() { int ret; @@ -884,6 +918,7 @@ void QgsSpatiaLiteProvider::loadFields() QString sql; mAttributeFields.clear(); + mDefaultValues.clear(); if ( !mIsQuery ) { @@ -921,6 +956,8 @@ void QgsSpatiaLiteProvider::loadFields() const TypeSubType fieldType = getVariantType( type ); mAttributeFields.append( QgsField( name, fieldType.first, type, 0, 0, QString(), fieldType.second ) ); } + + insertDefaultValue( i - 1, QString::fromUtf8( results[( i * columns ) + 4] ) ); } } sqlite3_free_table( results ); @@ -3820,8 +3857,10 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist ) } else if ( type == QVariant::String ) { + QString stringVal = v.toString(); + // binding a TEXT value - QByteArray ba = v.toString().toUtf8(); + QByteArray ba = stringVal.toUtf8(); sqlite3_bind_text( stmt, ++ia, ba.constData(), ba.size(), SQLITE_TRANSIENT ); } else if ( type == QVariant::StringList || type == QVariant::List ) @@ -4229,6 +4268,11 @@ QgsVectorDataProvider::Capabilities QgsSpatiaLiteProvider::capabilities() const return mEnabledCapabilities; } +QVariant QgsSpatiaLiteProvider::defaultValue( int fieldId ) const +{ + return mDefaultValues.value( fieldId, QVariant() ); +} + void QgsSpatiaLiteProvider::closeDb() { // trying to close the SQLite DB diff --git a/src/providers/spatialite/qgsspatialiteprovider.h b/src/providers/spatialite/qgsspatialiteprovider.h index 94295d20017..f1dabd4e743 100644 --- a/src/providers/spatialite/qgsspatialiteprovider.h +++ b/src/providers/spatialite/qgsspatialiteprovider.h @@ -165,6 +165,8 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider //! Returns a bitmask containing the supported capabilities QgsVectorDataProvider::Capabilities capabilities() const override; + QVariant defaultValue( int fieldId ) const override; + /** The SpatiaLite provider does its own transforms so we return * true for the following three functions to indicate that transforms * should not be handled by the QgsCoordinateTransform object. See the @@ -338,6 +340,9 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider //! Name of the geometry column in the table QString mGeometryColumn; + //! Map of field index to default value + QMap mDefaultValues; + //! Name of the SpatialIndex table QString mIndexTable; @@ -448,6 +453,8 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider void fetchConstraints(); + void insertDefaultValue( int fieldIndex, QString defaultVal ); + enum GEOS_3D { GEOS_3D_POINT = -2147483647, diff --git a/tests/src/python/test_provider_spatialite.py b/tests/src/python/test_provider_spatialite.py index f0d38b13f6c..bf5fb4819a7 100644 --- a/tests/src/python/test_provider_spatialite.py +++ b/tests/src/python/test_provider_spatialite.py @@ -139,6 +139,10 @@ class TestQgsSpatialiteProvider(unittest.TestCase, ProviderTestCase): sql = "CREATE TABLE test_constraints(id INTEGER PRIMARY KEY, num INTEGER NOT NULL, desc TEXT UNIQUE, desc2 TEXT, num2 INTEGER NOT NULL UNIQUE)" cur.execute(sql) + # simple table with defaults + sql = "CREATE TABLE test_defaults (id INTEGER NOT NULL PRIMARY KEY, name TEXT DEFAULT 'qgis ''is good', number INTEGER DEFAULT 5, number2 REAL DEFAULT 5.7, no_default REAL)" + cur.execute(sql) + cur.execute("COMMIT") con.close() @@ -461,6 +465,16 @@ class TestQgsSpatialiteProvider(unittest.TestCase, ProviderTestCase): self.assertTrue(vl.commitChanges()) + def testDefaultValues(self): + + l = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" % self.dbname, "test_defaults", "spatialite") + self.assertTrue(l.isValid()) + + self.assertEqual(l.dataProvider().defaultValue(1), "qgis 'is good") + self.assertEqual(l.dataProvider().defaultValue(2), 5) + self.assertEqual(l.dataProvider().defaultValue(3), 5.7) + self.assertFalse(l.dataProvider().defaultValue(4)) + if __name__ == '__main__': unittest.main()