Skip to content
Permalink
Browse files

Merge pull request #715 from Oslandia/issue7550

solves Issue7550
  • Loading branch information
jef-n committed Jul 16, 2013
2 parents 2fa7736 + 45ab8cc commit 29a4bc0aca96af9d662d263c0eadff6025f9c183
@@ -340,7 +340,7 @@ bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors )
//
// delete features
//
if ( !mDeletedFeatureIds.isEmpty() )
if ( success && !mDeletedFeatureIds.isEmpty() )
{
if (( cap & QgsVectorDataProvider::DeleteFeatures ) && provider->deleteFeatures( mDeletedFeatureIds ) )
{
@@ -366,7 +366,7 @@ bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors )
//
// add features
//
if ( !mAddedFeatures.isEmpty() )
if ( success && !mAddedFeatures.isEmpty() )
{
if ( cap & QgsVectorDataProvider::AddFeatures )
{
@@ -418,7 +418,7 @@ bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors )
//
// update geometries
//
if ( !mChangedGeometries.isEmpty() )
if ( success && !mChangedGeometries.isEmpty() )
{
if (( cap & QgsVectorDataProvider::ChangeGeometries ) && provider->changeGeometryValues( mChangedGeometries ) )
{
@@ -244,15 +244,19 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bo
QgsFeature newFeature;
newFeature.setGeometry( newGeometry );

//use default value where possible (primary key issue), otherwise the value from the original (split) feature
//use default value where possible for primary key (e.g. autoincrement),
//and use the value from the original (split) feature if not primary key
QgsAttributes newAttributes = select_it->attributes();
QVariant defaultValue;
for ( int j = 0; j < newAttributes.count(); ++j )
foreach ( int pkIdx, L->dataProvider()->pkAttributeIndexes() )
{
defaultValue = L->dataProvider()->defaultValue( j );
const QVariant defaultValue = L->dataProvider()->defaultValue( pkIdx );
if ( !defaultValue.isNull() )
{
newAttributes[ j ] = defaultValue;
newAttributes[ pkIdx ] = defaultValue;
}
else //try with NULL
{
newAttributes[ pkIdx ] = QVariant();
}
}

@@ -598,6 +598,7 @@ void QgsSpatiaLiteProvider::loadFieldsAbstractInterface( gaiaVectorLayerPtr lyr

attributeFields.clear();
mPrimaryKey.clear(); // cazzo cazzo cazzo
mPrimaryKeyAttrs.clear();

gaiaLayerAttributeFieldPtr fld = lyr->First;
if ( fld == NULL )
@@ -693,6 +694,7 @@ void QgsSpatiaLiteProvider::loadFields()
if ( !isQuery )
{
mPrimaryKey.clear();
mPrimaryKeyAttrs.clear();

sql = QString( "PRAGMA table_info(%1)" ).arg( quotedIdentifier( mTableName ) );

@@ -713,6 +715,8 @@ void QgsSpatiaLiteProvider::loadFields()
// found a Primary Key column
pkCount++;
pkName = name;
mPrimaryKeyAttrs << i - 1;
QgsDebugMsg( "found primaryKey " + name );
}

if ( name != mGeometryColumn )
@@ -778,6 +782,8 @@ void QgsSpatiaLiteProvider::loadFields()
{
pkCount++;
pkName = name;
mPrimaryKeyAttrs << i - 1;
QgsDebugMsg( "found primaryKey " + name );
}

if ( name != mGeometryColumn )
@@ -5211,3 +5217,9 @@ QGISEXTERN bool deleteLayer( const QString& dbPath, const QString& tableName, QS

return true;
}

QgsAttributeList QgsSpatiaLiteProvider::pkAttributeIndexes()
{
return mPrimaryKeyAttrs;
}

@@ -124,10 +124,6 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
*/
virtual void updateExtents();

/** * Get the name of the primary key for the layer
*/
QString getPrimaryKey();

/**
* Get the field information for the layer
* @return vector of QgsField objects
@@ -224,6 +220,12 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
*/
QString description() const;

/**
* Return list of indexes of fields that make up the primary key
* @note added in 2.0
*/
QgsAttributeList pkAttributeIndexes();

signals:
/**
* This is emitted whenever the worker thread has fully calculated the
@@ -301,6 +303,10 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
* Name of the primary key column in the table
*/
QString mPrimaryKey;
/**
* List of primary key columns in the table
*/
QgsAttributeList mPrimaryKeyAttrs;
/**
* Name of the geometry column in the table
*/
@@ -24,3 +24,4 @@ ADD_PYTHON_TEST(PyQgsComposerLabel test_qgscomposerlabel.py)
ADD_PYTHON_TEST(PyQgsExpression test_qgsexpression.py)
#ADD_PYTHON_TEST(PyQgsPalLabeling test_qgspallabeling.py)
ADD_PYTHON_TEST(PyQgsVectorFileWriter test_qgsvectorfilewriter.py)
ADD_PYTHON_TEST(PyQgsSpatialiteProvider test_qgsspatialiteprovider.py)
@@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsSpatialiteProvider
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Vincent Mora'
__date__ = '09/07/2013'
__copyright__ = 'Copyright 2013, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import os

from qgis.core import *

from utilities import (getQgisTestApp,
TestCase,
unittest
)

from pyspatialite import dbapi2 as sqlite3

# Convenience instances in case you may need them
QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()


def die(error_message):
raise Exception(error_message)

class TestQgsSpatialiteProvider(TestCase):

@classmethod
def setUpClass(cls):
"""Run before all tests"""
# create test db
if os.path.exists("test.sqlite") :
os.remove("test.sqlite")
con = sqlite3.connect("test.sqlite")
cur = con.cursor()
sql = "SELECT InitSpatialMetadata()"
cur.execute(sql)

# simple table with primary key
sql = "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_pg', 'geometry', 4326, 'POLYGON', 'XY')"
cur.execute(sql)
sql = "INSERT INTO test_pg (id, name, geometry) "
sql += "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
cur.execute(sql)

# table with multiple column primary key
sql = "CREATE TABLE test_pg_mk (id INTEGER NOT NULL, name TEXT NOT NULL, PRIMARY KEY(id,name))"
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_pg_mk', 'geometry', 4326, 'POLYGON', 'XY')"
cur.execute(sql)
sql = "INSERT INTO test_pg_mk (id, name, geometry) "
sql += "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
cur.execute(sql)

con.commit()
con.close()

@classmethod
def tearDownClass(cls):
"""Run after all tests"""
# for the time beeing, keep the file to check with qgis
#if os.path.exists("test.sqlite") :
# os.remove("test.sqlite")
pass

def setUp(self):
"""Run before each test."""
pass

def tearDown(self):
"""Run after each test."""
pass

def test_SplitFeature(self):
"""Create spatialite database"""
layer = QgsVectorLayer("dbname=test.sqlite table=test_pg (geometry)", "test_pg", "spatialite")
assert(layer.isValid())
assert(layer.hasGeometryType())
layer.startEditing()
layer.splitFeatures([QgsPoint(0.5, -0.5), QgsPoint(0.5, 1.5)], 0)==0 or die("error in split")
layer.splitFeatures([QgsPoint(-0.5, 0.5), QgsPoint(1.5, 0.5)], 0)==0 or die("error in split")
layer.commitChanges() or die("this commit should work")
layer.featureCount() == 4 or die("we should have 4 features after 2 split")

def test_SplitFeatureWithFailedCommit(self):
"""Create spatialite database"""
layer = QgsVectorLayer("dbname=test.sqlite table=test_pg_mk (geometry)", "test_pg_mk", "spatialite")
assert(layer.isValid())
assert(layer.hasGeometryType())
layer.startEditing()
layer.splitFeatures([QgsPoint(0.5, -0.5), QgsPoint(0.5, 1.5)], 0)==0 or die("error in split")
layer.splitFeatures([QgsPoint(-0.5, 0.5), QgsPoint(1.5, 0.5)], 0)==0 or die("error in split")
if layer.commitChanges():
die("this commit should fail")
layer.rollBack()
feat = QgsFeature()
it=layer.getFeatures()
it.nextFeature(feat)
ref = [[(0,0), (1,0), (1,1), (0,1), (0,0)]]
res = feat.geometry().asPolygon()
for ring1, ring2 in zip(ref ,res):
for p1, p2 in zip(ring1, ring2):
for c1, c2 in zip(p1,p2):
c1 == c2 or die("polygon has been altered by failed edition")

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


0 comments on commit 29a4bc0

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