From 45037eb0601e2f48ae548e2cd28b29b429644870 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 1 Dec 2016 20:29:06 +0100 Subject: [PATCH] OGR: add a "wfs_use_default_extent_for_getfeature" "yes" LAYER.METADATA When this is defined and a WFS request has no BBOX filter, do not use the MAP.EXTENT as a default BBX filter, which can hurt performance and is useless if MAP.EXTENT covers the whole layer. CREDITS: Funded by: Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale (CIG: 644544015A) --- mapogcfilter.c | 14 ++++++- mapogr.cpp | 12 ++++-- mapquery.c | 4 +- mapserver.h | 4 +- mapwfs.c | 12 +++++- ..._disable_default_extent_for_getfeature.xml | 38 +++++++++++++++++++ .../wxs/expected/wfs_ogr_native_sql_42.xml | 38 +++++++++++++++++++ msautotest/wxs/wfs_ogr_native_sql.map | 28 ++++++++++++++ 8 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 msautotest/wxs/expected/wfs_ogr_native_sql_06_disable_default_extent_for_getfeature.xml create mode 100644 msautotest/wxs/expected/wfs_ogr_native_sql_42.xml diff --git a/mapogcfilter.c b/mapogcfilter.c index 04d03e4ffd..0c226e180b 100644 --- a/mapogcfilter.c +++ b/mapogcfilter.c @@ -667,9 +667,19 @@ int FLTLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, mapObj *map, pszExpression = FLTGetCommonExpression(psNode, lp); if (pszExpression) { + const char* pszUseDefaultExtent; FilterEncodingNode* psTopBBOX; rectObj rect = map->extent; + pszUseDefaultExtent = msOWSLookupMetadata(&(lp->metadata), "F", + "use_default_extent_for_getfeature"); + if( pszUseDefaultExtent && CSLTestBoolean(pszUseDefaultExtent) && + lp->connectiontype == MS_OGR ) + { + const rectObj rectInvalid = MS_INIT_INVALID_RECT; + rect = rectInvalid; + } + psTopBBOX = FLTGetTopBBOX(psNode); if( psTopBBOX ) { @@ -706,9 +716,9 @@ int FLTLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, mapObj *map, if(map->debug == MS_DEBUGLEVEL_VVV) { if( pszExpression ) - msDebug("FLTLayerApplyPlainFilterToLayer(): %s, rect=%f,%f,%f,%f\n", pszExpression, rect.minx, rect.miny, rect.maxx, rect.maxy); + msDebug("FLTLayerApplyPlainFilterToLayer(): %s, rect=%.15g,%.15g,%.15g,%.15g\n", pszExpression, rect.minx, rect.miny, rect.maxx, rect.maxy); else - msDebug("FLTLayerApplyPlainFilterToLayer(): rect=%f,%f,%f,%f\n", rect.minx, rect.miny, rect.maxx, rect.maxy); + msDebug("FLTLayerApplyPlainFilterToLayer(): rect=%.15g,%.15g,%.15g,%.15g\n", rect.minx, rect.miny, rect.maxx, rect.maxy); } status = FLTApplyFilterToLayerCommonExpressionWithRect(map, iLayerIndex, diff --git a/mapogr.cpp b/mapogr.cpp index 97529a8786..45c54d0100 100644 --- a/mapogr.cpp +++ b/mapogr.cpp @@ -2092,6 +2092,8 @@ static int msOGRFileWhichShapes(layerObj *layer, rectObj rect, msOGRFileInfo *ps } char *select = (psInfo->pszSelect) ? msStrdup(psInfo->pszSelect) : NULL; + const rectObj rectInvalid = MS_INIT_INVALID_RECT; + bool bIsValidRect = memcmp(&rect, &rectInvalid, sizeof(rect)) != 0; // we'll go strictly two possible ways: // 1) GetLayer + SetFilter @@ -2192,13 +2194,15 @@ static int msOGRFileWhichShapes(layerObj *layer, rectObj rect, msOGRFileInfo *ps rect.miny = MAX(psInfo->rect.miny, rect.miny); rect.maxx = MIN(psInfo->rect.maxx, rect.maxx); rect.maxy = MIN(psInfo->rect.maxy, rect.maxy); + bIsValidRect = true; } psInfo->rect = rect; bool bSpatialiteAddOrderByFID = false; if( psInfo->dialect && EQUAL(psInfo->dialect, "Spatialite") && - psInfo->pszMainTableName != NULL && psInfo->bHasSpatialIndex ) + psInfo->pszMainTableName != NULL && psInfo->bHasSpatialIndex && + bIsValidRect ) { select = msStringConcatenate(select, " JOIN "); @@ -2255,7 +2259,7 @@ static int msOGRFileWhichShapes(layerObj *layer, rectObj rect, msOGRFileInfo *ps bool bOffsetAlreadyAdded = false; // use spatial index - if (psInfo->dialect) { + if (psInfo->dialect && bIsValidRect ) { if (EQUAL(psInfo->dialect, "PostgreSQL")) { if (filter) filter = msStringConcatenate(filter, " AND"); const char *col = OGR_L_GetGeometryColumn(psInfo->hLayer); // which geom field?? @@ -2391,7 +2395,7 @@ static int msOGRFileWhichShapes(layerObj *layer, rectObj rect, msOGRFileInfo *ps ACQUIRE_OGR_LOCK; - if( OGR_L_GetGeomType( psInfo->hLayer ) != wkbNone ) { + if( OGR_L_GetGeomType( psInfo->hLayer ) != wkbNone && bIsValidRect ) { if (rect.minx == rect.maxx && rect.miny == rect.maxy) { OGRGeometryH hSpatialFilterPoint = OGR_G_CreateGeometry( wkbPoint ); @@ -2423,7 +2427,7 @@ static int msOGRFileWhichShapes(layerObj *layer, rectObj rect, msOGRFileInfo *ps psInfo->rect = rect; if (layer->debug >= MS_DEBUGLEVEL_VVV) - msDebug("msOGRFileWhichShapes: Setting spatial filter to %f %f %f %f\n", rect.minx, rect.miny, rect.maxx, rect.maxy ); + msDebug("msOGRFileWhichShapes: Setting spatial filter to %.15g %.15g %.15g %.15g\n", rect.minx, rect.miny, rect.maxx, rect.maxy ); /* ------------------------------------------------------------------ * Apply an attribute filter if we have one prefixed with a WHERE diff --git a/mapquery.c b/mapquery.c index a94ccb16e1..968354a514 100644 --- a/mapquery.c +++ b/mapquery.c @@ -670,6 +670,7 @@ int msQueryByFilter(mapObj *map) expressionObj old_filter; rectObj search_rect; + const rectObj invalid_rect = MS_INIT_INVALID_RECT; shapeObj shape; @@ -761,9 +762,10 @@ int msQueryByFilter(mapObj *map) if(status != MS_SUCCESS) goto query_error; search_rect = map->query.rect; + #ifdef USE_PROJ lp->project = msProjectionsDiffer(&(lp->projection), &(map->projection)); - if(lp->project) + if(lp->project && memcmp( &search_rect, &invalid_rect, sizeof(search_rect) ) != 0 ) msProjectRect(&(map->projection), &(lp->projection), &search_rect); /* project the searchrect to source coords */ #endif diff --git a/mapserver.h b/mapserver.h index 042403eb0d..e756d9a349 100644 --- a/mapserver.h +++ b/mapserver.h @@ -474,7 +474,9 @@ extern "C" { #define MS_IS_VALID_ARRAY_INDEX(index, size) ((index<0 || index>=size)?MS_FALSE:MS_TRUE) #define MS_CONVERT_UNIT(src_unit, dst_unit, value) (value * msInchesPerUnit(src_unit,0) / msInchesPerUnit(dst_unit,0)) - + +#define MS_INIT_INVALID_RECT { -1e300, -1e300, 1e300, 1e300 } + #endif /* General enumerated types - needed by scripts */ diff --git a/mapwfs.c b/mapwfs.c index 3656f17e09..bac3f218de 100644 --- a/mapwfs.c +++ b/mapwfs.c @@ -37,6 +37,7 @@ /* There is a dependency to GDAL/OGR for the GML driver and MiniXML parser */ #include "cpl_minixml.h" #include "cpl_conv.h" +#include "cpl_string.h" #include "mapogcfilter.h" #include "mapowscommon.h" @@ -2138,6 +2139,7 @@ static int msWFSRunBasicGetFeature(mapObj* map, const char *pszMapSRS=NULL, *pszLayerSRS=NULL; rectObj ext; int status; + const char* pszUseDefaultExtent; map->query.type = MS_QUERY_BY_RECT; /* setup the query */ map->query.mode = MS_QUERY_MULTIPLE; @@ -2149,7 +2151,15 @@ static int msWFSRunBasicGetFeature(mapObj* map, if(!paramsObj->pszSrs) pszMapSRS = msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "FO", MS_TRUE); - if (msOWSGetLayerExtent(map, lp, "FO", &ext) == MS_SUCCESS) { + pszUseDefaultExtent = msOWSLookupMetadata(&(lp->metadata), "F", + "use_default_extent_for_getfeature"); + if( pszUseDefaultExtent && CSLTestBoolean(pszUseDefaultExtent) && + lp->connectiontype == MS_OGR ) + { + const rectObj rectInvalid = MS_INIT_INVALID_RECT; + map->query.rect = rectInvalid; + } + else if (msOWSGetLayerExtent(map, lp, "FO", &ext) == MS_SUCCESS) { /* For a single point layer, to avoid numerical precision issues */ /* when reprojection is involved */ diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_06_disable_default_extent_for_getfeature.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_06_disable_default_extent_for_getfeature.xml new file mode 100644 index 0000000000..0528913985 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_06_disable_default_extent_for_getfeature.xml @@ -0,0 +1,38 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + 643513.360000,4896928.190000 643513.360000,4896928.190000 + + + + + + + + 643513.360000,4896928.190000 643513.360000,4896928.190000 + + + + + 643513.360000,4896928.190000 + + + Fanano + 2910 + 1 + 0 + 0 + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_42.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_42.xml new file mode 100644 index 0000000000..6bbe411da3 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_42.xml @@ -0,0 +1,38 @@ +Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 + + + + + + 672130.72000,4902785.47000 672130.72000,4902785.47000 + + + + + + + + 672130.72000,4902785.47000 672130.72000,4902785.47000 + + + + + 672130.72000,4902785.47000 + + + Grizzana Morandi + 3694 + 1 + 0 + 0 + + + + diff --git a/msautotest/wxs/wfs_ogr_native_sql.map b/msautotest/wxs/wfs_ogr_native_sql.map index 0073ece2da..3b9969177d 100644 --- a/msautotest/wxs/wfs_ogr_native_sql.map +++ b/msautotest/wxs/wfs_ogr_native_sql.map @@ -20,6 +20,9 @@ # # RUN_PARMS: wfs_ogr_native_sql_05.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=namefanano" > [RESULT] # RUN_PARMS: wfs_ogr_native_sql_06.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=nameFanano" > [RESULT] + +# RUN_PARMS: wfs_ogr_native_sql_06_disable_default_extent_for_getfeature.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns_disable_default_extent_for_getfeature&OUTPUTFORMAT=GML2&FILTER=nameFanano" > [RESULT] + # RUN_PARMS: wfs_ogr_native_sql_07.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=namefanano" > [RESULT] # RUN_PARMS: wfs_ogr_native_sql_08.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=nameFanano" > [RESULT] # @@ -90,6 +93,8 @@ # SortBy # RUN_PARMS: wfs_ogr_native_sql_41.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=towns&OUTPUTFORMAT=GML2&FILTER=nameFanano&SORTBY=name" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_ogr_native_sql_42.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAME=towns_disable_default_extent_for_getfeature&OUTPUTFORMAT=GML2&COUNT=1" > [RESULT_DEVERSION] + MAP NAME WFS_OGR_NATIVE_SQL_TEST @@ -146,6 +151,29 @@ LAYER TEMPLATE "wfs_ogr_native_sql.map" END # Layer +LAYER + NAME towns_disable_default_extent_for_getfeature + DATA towns + CONNECTIONTYPE OGR + CONNECTION "./data/db.sqlite" + PROCESSING "NATIVE_SQL=YES" + METADATA + "ows_title" "towns_disable_default_extent_for_getfeature" + "wfs_featureid" "ID" + "gml_include_items" "all" + "gml_types" "auto" + "wfs_getfeature_formatlist" "ogrgml" + "wfs_use_default_extent_for_getfeature" "yes" + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:32632" + END + + TEMPLATE "wfs_ogr_native_sql.map" +END # Layer + LAYER NAME towns_spatial_index_disabled DATA towns