Fix QgsVectorLayerExporter fails when provider launders layer name

Eg dropping a layer with spaces in its name onto a ESRI FileGeodatabase
in the browser
This commit is contained in:
Nyall Dawson 2025-03-05 12:01:29 +10:00
parent 9e8be2679a
commit 03174af446
3 changed files with 91 additions and 16 deletions

View File

@ -107,9 +107,9 @@ QgsVectorLayerExporter::QgsVectorLayerExporter( const QString &uri,
// create an empty layer
QString errMsg;
QgsProviderRegistry *pReg = QgsProviderRegistry::instance();
QString createdLayerName;
QString uriUpdated;
mError = pReg->createEmptyLayer( providerKey, uri, fields, geometryType, crs, overwrite, mOldToNewAttrIdx,
errMsg, !modifiedOptions.isEmpty() ? &modifiedOptions : nullptr, createdLayerName );
errMsg, !modifiedOptions.isEmpty() ? &modifiedOptions : nullptr, uriUpdated );
if ( errorCode() != Qgis::VectorExportResult::Success )
{
@ -128,20 +128,6 @@ QgsVectorLayerExporter::QgsVectorLayerExporter( const QString &uri,
QgsDebugMsgLevel( QStringLiteral( "Created empty layer" ), 2 );
QString uriUpdated( uri );
// HACK sorry...
if ( providerKey == QLatin1String( "ogr" ) )
{
QString layerName;
if ( options.contains( QStringLiteral( "layerName" ) ) )
layerName = options.value( QStringLiteral( "layerName" ) ).toString();
if ( !layerName.isEmpty() )
{
uriUpdated += QLatin1String( "|layername=" );
uriUpdated += layerName;
}
}
// Oracle specific HACK: we cannot guess the geometry type when there is no rows, so we need
// to force it in the uri
if ( providerKey == QLatin1String( "oracle" ) )

View File

@ -375,6 +375,7 @@ ADD_PYTHON_TEST(PyQgsVectorLayerCache test_qgsvectorlayercache.py)
ADD_PYTHON_TEST(PyQgsVectorLayerEditBuffer test_qgsvectorlayereditbuffer.py)
ADD_PYTHON_TEST(PyQgsVectorLayerEditBufferGroup test_qgsvectorlayereditbuffergroup.py)
ADD_PYTHON_TEST(PyQgsVectorLayerEditUtils test_qgsvectorlayereditutils.py)
ADD_PYTHON_TEST(PyQgsVectorLayerExporter test_qgsvectorlayerexporter.py)
ADD_PYTHON_TEST(PyQgsVectorLayerNamedStyle test_qgsvectorlayer_namedstyle.py)
ADD_PYTHON_TEST(PyQgsVectorLayerProfileGenerator test_qgsvectorlayerprofilegenerator.py)
ADD_PYTHON_TEST(PyQgsVectorLayerRenderer test_qgsvectorlayerrenderer.py)

View File

@ -0,0 +1,88 @@
"""QGIS Unit tests for QgsVectorLayerExporter.
.. 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.
"""
import tempfile
import unittest
from pathlib import Path
import osgeo.gdal # NOQA
from osgeo import gdal, ogr
from qgis.core import (
Qgis,
QgsVectorLayerExporter,
QgsFeature,
QgsGeometry,
QgsPointXY,
QgsVectorLayer,
)
from qgis.testing import start_app, QgisTestCase
from utilities import unitTestDataPath
TEST_DATA_DIR = unitTestDataPath()
start_app()
def GDAL_COMPUTE_VERSION(maj, min, rev):
return (maj) * 1000000 + (min) * 10000 + (rev) * 100
class TestQgsVectorLayerExporter(QgisTestCase):
@unittest.skipIf(
int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 8, 0),
"GDAL 3.8 required",
)
def test_write_laundered_table_names(self):
"""
Test exporting layer name with spaces to File Geodatabase, the name
should be laundered but things should still work
"""
with tempfile.TemporaryDirectory() as temp_dir:
dest_file_name = Path(temp_dir) / "test_export.gdb"
ds = ogr.GetDriverByName("OpenFileGDB").CreateDataSource(
dest_file_name.as_posix()
)
self.assertIsNotNone(ds)
del ds
# create a layer to export
layer = QgsVectorLayer(
"Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory"
)
self.assertTrue(layer.isValid())
pr = layer.dataProvider()
f = QgsFeature()
f.setAttributes(["test", 123])
f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
f2 = QgsFeature()
f2.setAttributes(["test2", 457])
f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
self.assertTrue(pr.addFeatures([f, f2]))
res, error = QgsVectorLayerExporter.exportLayer(
layer,
dest_file_name.as_posix(),
"ogr",
layer.crs(),
options={"layerName": "Must be Laundered", "update": True},
)
self.assertEqual(res, Qgis.VectorExportResult.Success)
# true to read result
layer = QgsVectorLayer(
dest_file_name.as_posix() + "|layername=Must_be_Laundered",
"test",
"ogr",
)
self.assertTrue(layer.isValid())
self.assertEqual(layer.featureCount(), 2)
if __name__ == "__main__":
unittest.main()