Skip to content

Commit 62cdb27

Browse files
author
Hugo Mercier
committed
Fix virtual layer definition parsing
1 parent 41c9da9 commit 62cdb27

File tree

4 files changed

+39
-18
lines changed

4 files changed

+39
-18
lines changed

src/core/qgsvirtuallayerdefinition.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ QgsVirtualLayerDefinition QgsVirtualLayerDefinition::fromUrl( const QUrl& url )
3939
QgsFields fields;
4040

4141
int layerIdx = 0;
42-
QList<QPair<QString, QString> > items = url.queryItems();
42+
QList<QPair<QByteArray, QByteArray> > items = url.encodedQueryItems();
4343
for ( int i = 0; i < items.size(); i++ )
4444
{
4545
QString key = items.at( i ).first;
@@ -130,7 +130,7 @@ QgsVirtualLayerDefinition QgsVirtualLayerDefinition::fromUrl( const QUrl& url )
130130
else if ( key == "query" )
131131
{
132132
// url encoded query
133-
def.setQuery( value );
133+
def.setQuery( QUrl::fromPercentEncoding( value.toUtf8() ) );
134134
}
135135
else if ( key == "field" )
136136
{
@@ -171,11 +171,11 @@ QUrl QgsVirtualLayerDefinition::toUrl() const
171171
if ( l.isReferenced() )
172172
url.addQueryItem( "layer_ref", QString( "%1:%2" ).arg( l.reference(), l.name() ) );
173173
else
174-
url.addQueryItem( "layer", QString( "%1:%4:%2:%3" ) // the order is important, since the 4th argument may contain '%2' as well
175-
.arg( l.provider(),
176-
QString( QUrl::toPercentEncoding( l.name() ) ),
177-
l.encoding(),
178-
QString( QUrl::toPercentEncoding( l.source() ) ) ) );
174+
url.addEncodedQueryItem( "layer", QString( "%1:%4:%2:%3" ) // the order is important, since the 4th argument may contain '%2' as well
175+
.arg( l.provider(),
176+
QString( QUrl::toPercentEncoding( l.name() ) ),
177+
l.encoding(),
178+
QString( QUrl::toPercentEncoding( l.source() ) ) ).toUtf8() );
179179
}
180180

181181
if ( !query().isEmpty() )

src/providers/virtual/qgsvirtuallayersqlitemodule.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,14 @@ struct VTable
126126
, mValid( true )
127127
{
128128
mProvider = static_cast<QgsVectorDataProvider*>( QgsProviderRegistry::instance()->provider( provider, source ) );
129-
if ( !mProvider || !mProvider->isValid() )
129+
if ( !mProvider )
130130
{
131131
throw std::runtime_error( "Invalid provider" );
132132
}
133+
else if ( mProvider && !mProvider->isValid() )
134+
{
135+
throw std::runtime_error(( "Provider error:" + mProvider->error().message() ).toUtf8().constData() );
136+
}
133137
if ( mProvider->capabilities() & QgsVectorDataProvider::SelectEncoding )
134138
{
135139
mProvider->setEncoding( mEncoding );

tests/src/python/test_provider_virtual.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
QgsRectangle,
2929
QgsErrorMessage,
3030
QgsProviderRegistry,
31-
QgsVirtualLayerDefinition
31+
QgsVirtualLayerDefinition,
32+
QgsWKBTypes
3233
)
3334

3435
from utilities import (unitTestDataPath,
@@ -84,7 +85,7 @@ def tearDown(self):
8485
pass
8586

8687
def test_CsvNoGeometry(self):
87-
l1 = QgsVectorLayer(os.path.join(self.testDataDir, "delimitedtext/test.csv") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
88+
l1 = QgsVectorLayer("file:///" + os.path.join(self.testDataDir, "delimitedtext/test.csv").replace("\\", "/") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
8889
self.assertEqual(l1.isValid(), True)
8990
QgsMapLayerRegistry.instance().addMapLayer(l1)
9091

@@ -95,7 +96,7 @@ def test_CsvNoGeometry(self):
9596

9697
def test_source_escaping(self):
9798
# the source contains ':'
98-
source = "file:///" + os.path.join(self.testDataDir, "delimitedtext/test.csv") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no"
99+
source = "file:///" + os.path.join(self.testDataDir, "delimitedtext/test.csv").replace("\\", "/") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no"
99100
d = QgsVirtualLayerDefinition()
100101
d.addSource("t", source, "delimitedtext")
101102
l = QgsVectorLayer(d.toString(), "vtab", "virtual", False)
@@ -134,7 +135,7 @@ def create_test_db(dbfile):
134135
self.assertEqual(l.isValid(), True)
135136

136137
def test_DynamicGeometry(self):
137-
l1 = QgsVectorLayer(os.path.join(self.testDataDir, "delimitedtext/testextpt.txt") + "?type=csv&delimiter=%7C&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
138+
l1 = QgsVectorLayer("file:///" + os.path.join(self.testDataDir, "delimitedtext/testextpt.txt").replace("\\", "/") + "?type=csv&delimiter=%7C&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
138139
self.assertEqual(l1.isValid(), True)
139140
QgsMapLayerRegistry.instance().addMapLayer(l1)
140141

@@ -327,7 +328,10 @@ def test_recursiveLayer(self):
327328

328329
def test_no_geometry(self):
329330
source = QUrl.toPercentEncoding(os.path.join(self.testDataDir, "france_parts.shp"))
330-
l2 = QgsVectorLayer("?layer=ogr:%s:vtab&nogeometry" % source, "vtab2", "virtual", False)
331+
df = QgsVirtualLayerDefinition()
332+
df.addSource("vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr")
333+
df.setGeometryWkbType(QgsWKBTypes.NoGeometry)
334+
l2 = QgsVectorLayer(df.toString(), "vtab2", "virtual", False)
331335
self.assertEqual(l2.isValid(), True)
332336
self.assertEqual(l2.dataProvider().geometryType(), 100) # NoGeometry
333337

@@ -386,7 +390,7 @@ def test_reopen4(self):
386390
self.assertEqual(suma, 3064.0)
387391

388392
def test_refLayer(self):
389-
l1 = QgsVectorLayer(os.path.join(self.testDataDir, "delimitedtext/test.csv") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
393+
l1 = QgsVectorLayer("file:///" + os.path.join(self.testDataDir, "delimitedtext/test.csv").replace("\\", "/") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
390394
self.assertEqual(l1.isValid(), True)
391395
QgsMapLayerRegistry.instance().addMapLayer(l1)
392396

@@ -399,7 +403,7 @@ def test_refLayer(self):
399403
print sum([f.id() for f in l2.getFeatures()])
400404

401405
def test_refLayers(self):
402-
l1 = QgsVectorLayer(os.path.join(self.testDataDir, "delimitedtext/test.csv") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
406+
l1 = QgsVectorLayer("file:///" + os.path.join(self.testDataDir, "delimitedtext/test.csv").replace("\\", "/") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
403407
self.assertEqual(l1.isValid(), True)
404408
QgsMapLayerRegistry.instance().addMapLayer(l1)
405409

@@ -414,7 +418,7 @@ def test_refLayers(self):
414418
QgsMapLayerRegistry.instance().removeMapLayer(l2.id())
415419

416420
def test_refLayers2(self):
417-
l1 = QgsVectorLayer(os.path.join(self.testDataDir, "delimitedtext/test.csv") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
421+
l1 = QgsVectorLayer("file:///" + os.path.join(self.testDataDir, "delimitedtext/test.csv").replace("\\", "/") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
418422
self.assertEqual(l1.isValid(), True)
419423
QgsMapLayerRegistry.instance().addMapLayer(l1)
420424

@@ -425,7 +429,7 @@ def test_refLayers2(self):
425429
self.assertEqual("Cannot store referenced layers" in l2.dataProvider().error().message(), True)
426430

427431
def test_sql(self):
428-
l1 = QgsVectorLayer(os.path.join(self.testDataDir, "delimitedtext/test.csv") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
432+
l1 = QgsVectorLayer("file:///" + os.path.join(self.testDataDir, "delimitedtext/test.csv").replace("\\", "/") + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
429433
self.assertEqual(l1.isValid(), True)
430434
QgsMapLayerRegistry.instance().addMapLayer(l1)
431435

tests/src/python/test_qgsvirtuallayerdefinition.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
from utilities import (TestCase, unittest)
2525

26-
from PyQt4.QtCore import QVariant
26+
from PyQt4.QtCore import QVariant, QUrl
2727

2828

2929
class TestQgsVirtualLayerDefinition(TestCase):
@@ -34,32 +34,45 @@ def test1(self):
3434
d.setFilePath("/file")
3535
self.assertEqual(d.toString(), "/file")
3636
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).filePath(), "/file")
37+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(d.toString())).filePath(), "/file")
3738
d.setFilePath("C:\\file")
3839
self.assertEqual(d.toString(), "C:%5Cfile")
3940
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).filePath(), "C:\\file")
4041
d.setQuery("SELECT * FROM mytable")
4142
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).query(), "SELECT * FROM mytable")
43+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(d.toString())).query(), "SELECT * FROM mytable")
4244

4345
q = u"SELECT * FROM tableéé /*:int*/"
4446
d.setQuery(q)
4547
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).query(), q)
48+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(d.toString())).query(), q)
4649

4750
s1 = u"file://foo&bar=okié"
4851
d.addSource("name", s1, "provider", "utf8")
4952
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[0].source(), s1)
53+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(d.toString())).sourceLayers()[0].source(), s1)
5054

5155
n1 = u"éé ok"
5256
d.addSource(n1, s1, "provider")
5357
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[1].name(), n1)
58+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(d.toString())).sourceLayers()[1].name(), n1)
5459

5560
d.addSource("ref1", "id0001")
5661
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[2].reference(), "id0001")
62+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(d.toString())).sourceLayers()[2].reference(), "id0001")
63+
64+
s = "dbname='C:\\tt' table=\"test\" (geometry) sql="
65+
d.addSource("nn", s, "spatialite")
66+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[3].source(), s)
67+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(d.toString())).sourceLayers()[3].source(), s)
5768

5869
d.setGeometryField("geom")
5970
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).geometryField(), "geom")
71+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(d.toString())).geometryField(), "geom")
6072

6173
d.setGeometryWkbType(QgsWKBTypes.Point)
6274
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).geometryWkbType(), QgsWKBTypes.Point)
75+
self.assertEqual(QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(d.toString())).geometryWkbType(), QgsWKBTypes.Point)
6376

6477
f = QgsFields()
6578
f.append(QgsField("a", QVariant.Int))

0 commit comments

Comments
 (0)