diff --git a/src/server/services/wms/qgswmsrenderer.cpp b/src/server/services/wms/qgswmsrenderer.cpp index 229ce83ac28e..e2966dabb132 100644 --- a/src/server/services/wms/qgswmsrenderer.cpp +++ b/src/server/services/wms/qgswmsrenderer.cpp @@ -362,18 +362,22 @@ namespace QgsWms else { const QgsAttributeList pkIndexes = cLayer->primaryKeyAttributes(); - if ( pkIndexes.size() < 1 ) + if ( pkIndexes.size() == 0 ) { - throw QgsException( QStringLiteral( "An error occurred during the Atlas print" ) ); + QgsDebugMsgLevel( QStringLiteral( "Atlas print: layer %1 has no primary key attributes" ).arg( cLayer->name() ), 2 ); } + + // Handles the pk-less case + const int pkIndexesSize {std::max( pkIndexes.size(), 1 )}; + QStringList pkAttributeNames; - for ( int pkIndex : pkIndexes ) + for ( int pkIndex : std::as_const( pkIndexes ) ) { pkAttributeNames.append( cLayer->fields().at( pkIndex ).name() ); } - int nAtlasFeatures = atlasPk.size() / pkIndexes.size(); - if ( nAtlasFeatures * pkIndexes.size() != atlasPk.size() ) //Test is atlasPk.size() is a multiple of pkIndexes.size(). Bail out if not + const int nAtlasFeatures = atlasPk.size() / pkIndexesSize; + if ( nAtlasFeatures * pkIndexesSize != atlasPk.size() ) //Test if atlasPk.size() is a multiple of pkIndexesSize. Bail out if not { throw QgsBadRequestException( QgsServiceException::QGIS_InvalidParameterValue, QStringLiteral( "Wrong number of ATLAS_PK parameters" ) ); @@ -383,7 +387,7 @@ namespace QgsWms if ( nAtlasFeatures > maxAtlasFeatures ) { throw QgsBadRequestException( QgsServiceException::QGIS_InvalidParameterValue, - QString( "%1 atlas features have been requestet, but the project configuration only allows printing %2 atlas features at a time" ) + QString( "%1 atlas features have been requested, but the project configuration only allows printing %2 atlas features at a time" ) .arg( nAtlasFeatures ).arg( maxAtlasFeatures ) ); } @@ -399,14 +403,23 @@ namespace QgsWms filterString.append( "( " ); - for ( int j = 0; j < pkIndexes.size(); ++j ) + // If the layer has no PK attributes, assume FID + if ( pkAttributeNames.isEmpty() ) { - if ( j > 0 ) + filterString.append( QStringLiteral( "$id = %1" ).arg( atlasPk.at( currentAtlasPk ) ) ); + ++currentAtlasPk; + } + else + { + for ( int j = 0; j < pkIndexes.size(); ++j ) { - filterString.append( " AND " ); + if ( j > 0 ) + { + filterString.append( " AND " ); + } + filterString.append( QgsExpression::createFieldEqualityExpression( pkAttributeNames.at( j ), atlasPk.at( currentAtlasPk ) ) ); + ++currentAtlasPk; } - filterString.append( QString( "\"%1\" = %2" ).arg( pkAttributeNames.at( j ), atlasPk.at( currentAtlasPk ) ) ); - ++currentAtlasPk; } filterString.append( " )" ); @@ -417,7 +430,7 @@ namespace QgsWms atlas->setFilterExpression( filterString, errorString ); if ( !errorString.isEmpty() ) { - throw QgsException( QStringLiteral( "An error occurred during the Atlas print" ) ); + throw QgsException( QStringLiteral( "An error occurred during the Atlas print: %1" ).arg( errorString ) ); } } } diff --git a/tests/src/python/test_qgsserver_wms_getprint_atlas.py b/tests/src/python/test_qgsserver_wms_getprint_atlas.py index 9251982ff281..2cefd2db0aef 100644 --- a/tests/src/python/test_qgsserver_wms_getprint_atlas.py +++ b/tests/src/python/test_qgsserver_wms_getprint_atlas.py @@ -22,9 +22,11 @@ import urllib.parse from qgis.testing import unittest - +from utilities import unitTestDataPath from test_qgsserver import QgsServerTestBase +from qgis.core import QgsProject + class TestQgsServerWMSGetPrintAtlas(QgsServerTestBase): """QGIS Server WMS Tests for GetPrint atlas request""" @@ -55,6 +57,25 @@ def test_wms_getprint_atlas_getProjectSettings(self): self.assertTrue('atlasEnabled="1"' in str(r)) self.assertTrue('' in str(r)) + def test_wms_getprint_atlas_no_pk(self): + """Test issue GH #30817""" + + project = QgsProject() + self.assertTrue(project.read(os.path.join(unitTestDataPath(), 'qgis_server', 'bug_gh30817_atlas_pk.qgs'))) + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetPrint", + "TEMPLATE": "layout_csv", + "TRANSPARENT": "true", + "FORMAT": "png", + "DPI": "50", + "CRS": "EPSG:2056", + "ATLAS_PK": "2", + }.items())]) + r, h = self._result(self._execute_request_project(qs, project)) + self._img_diff_error(r, h, "WMS_GetPrint_Atlas_No_Pk") + if __name__ == '__main__': unittest.main() diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Atlas_No_Pk/WMS_GetPrint_Atlas_No_Pk.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Atlas_No_Pk/WMS_GetPrint_Atlas_No_Pk.png new file mode 100644 index 000000000000..26ec5f41687f Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Atlas_No_Pk/WMS_GetPrint_Atlas_No_Pk.png differ diff --git a/tests/testdata/qgis_server/bug_gh30817_atlas_pk.qgs b/tests/testdata/qgis_server/bug_gh30817_atlas_pk.qgs new file mode 100644 index 000000000000..ff4359e4d448 --- /dev/null +++ b/tests/testdata/qgis_server/bug_gh30817_atlas_pk.qgs @@ -0,0 +1,808 @@ + + + + + + + + + + PROJCRS["WGS 84 / Pseudo-Mercator",BASEGEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["Popular Visualisation Pseudo-Mercator",METHOD["Popular Visualisation Pseudo Mercator",ID["EPSG",1024]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["False easting",0,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Web mapping and visualisation."],AREA["World between 85.06°S and 85.06°N."],BBOX[-85.06,-180,85.06,180]],ID["EPSG",3857]] + +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs + 3857 + 3857 + EPSG:3857 + WGS 84 / Pseudo-Mercator + merc + EPSG:7030 + false + + + + + + + + + + + data_34a17c5e_39a1_493a_af95_b5a233b40db1 + + + + + + + + + + + meters + + -2217275.19168864423409104 + 3779713.49600001005455852 + -2217273.09938558330759406 + 3779715.24036237737163901 + + 0 + + + PROJCRS["WGS 84 / Pseudo-Mercator",BASEGEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["Popular Visualisation Pseudo-Mercator",METHOD["Popular Visualisation Pseudo Mercator",ID["EPSG",1024]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["False easting",0,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Web mapping and visualisation."],AREA["World between 85.06°S and 85.06°N."],BBOX[-85.06,-180,85.06,180]],ID["EPSG",3857]] + +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs + 3857 + 3857 + EPSG:3857 + WGS 84 / Pseudo-Mercator + merc + EPSG:7030 + false + + + 0 + + + + + + + + + + + + Annotations_c1e8b38e_61dd_49f2_8dc3_36f4fd4a02fd + + + + + Annotations + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + 1 + 0 + + + + + + 3.97240340488328014 + 45.15886406139620135 + 5.44448585846197997 + 46.14132936036769905 + + + -19.91812149041812674 + 32.12487455193483754 + -19.91810358996271191 + 32.12488719067417264 + + data_34a17c5e_39a1_493a_af95_b5a233b40db1 + ./bug_gh30817_atlas_pk_data.csv + + + + data_csv + + + PROJCRS["CH1903+ / LV95",BASEGEOGCRS["CH1903+",DATUM["CH1903+",ELLIPSOID["Bessel 1841",6377397.155,299.1528128,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4150]],CONVERSION["Swiss Oblique Mercator 1995",METHOD["Hotine Oblique Mercator (variant B)",ID["EPSG",9815]],PARAMETER["Latitude of projection centre",46.9524055555556,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8811]],PARAMETER["Longitude of projection centre",7.43958333333333,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8812]],PARAMETER["Azimuth of initial line",90,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8813]],PARAMETER["Angle from Rectified to Skew Grid",90,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8814]],PARAMETER["Scale factor on initial line",1,SCALEUNIT["unity",1],ID["EPSG",8815]],PARAMETER["Easting at projection centre",2600000,LENGTHUNIT["metre",1],ID["EPSG",8816]],PARAMETER["Northing at projection centre",1200000,LENGTHUNIT["metre",1],ID["EPSG",8817]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Cadastre, engineering survey, topographic mapping (large and medium scale)."],AREA["Liechtenstein; Switzerland."],BBOX[45.82,5.96,47.81,10.49]],ID["EPSG",2056]] + +proj=somerc +lat_0=46.9524055555556 +lon_0=7.43958333333333 +k_0=1 +x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs + 47 + 2056 + EPSG:2056 + CH1903+ / LV95 + somerc + EPSG:7004 + false + + + + + + + dataset + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + ogr + + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + "WKT" + + + + + + + + + + + + + 1 + true + + + 0 + + + 255 + 255 + 255 + 255 + 0 + 255 + 255 + + + false + + + + + + EPSG:7030 + + + m2 + meters + + + 5 + 2.5 + false + false + 1 + 0 + false + false + true + 0 + 255,0,0,255 + + + false + + + true + 2 + MU + + false + + 1 + + + + + + + + + + + None + false + + + + + + 1 + false + conditions unknown + 90 + + + + 100 + + 8 + + false + + false + + 0 + + false + + + + + + + + false + + + + + false + + 5000 + + + + false + + + + 10 + + 1024 + singleLayer + 0 + online + 0 + + + + + + + + + + + + + + + + + + + + + + + + + Olivier + 2021-10-13T14:25:13 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PROJCRS["WGS 84 / Pseudo-Mercator",BASEGEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["Popular Visualisation Pseudo-Mercator",METHOD["Popular Visualisation Pseudo Mercator",ID["EPSG",1024]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["False easting",0,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["easting (X)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["northing (Y)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Web mapping and visualisation."],AREA["World between 85.06°S and 85.06°N."],BBOX[-85.06,-180,85.06,180]],ID["EPSG",3857]] + +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs + 3857 + 3857 + EPSG:3857 + WGS 84 / Pseudo-Mercator + merc + EPSG:7030 + false + + + + + + + + + + diff --git a/tests/testdata/qgis_server/bug_gh30817_atlas_pk_data.csv b/tests/testdata/qgis_server/bug_gh30817_atlas_pk_data.csv new file mode 100644 index 000000000000..c0a58eb04b2e --- /dev/null +++ b/tests/testdata/qgis_server/bug_gh30817_atlas_pk_data.csv @@ -0,0 +1,4 @@ +WKT, +"POLYGON ((4.8452965180606 46.1362035978033,4.94146270849539 45.8947544654919,5.21516648127133 45.9153443716443,5.16338468642183 46.1413293603677,4.8452965180606 46.1362035978033))" +"POLYGON ((4.35706816662244 45.7916903788217,4.40145256220773 45.4865387880861,4.06856959531807 45.5280126703756,3.97240340488328 45.786532162445,4.35706816662244 45.7916903788217))" +"POLYGON ((5.08201329451547 45.4138859638244,5.01543670113754 45.2787109954903,5.43708845919777 45.1588640613962,5.44448585846198 45.3827203902239,5.08201329451547 45.4138859638244))"