Permalink
Browse files

msOGRFileWhichShapes(): fix taking into account of filters (#4974)

Should fix wfsogr10_twolayer.xml
  • Loading branch information...
rouault committed Sep 20, 2014
1 parent 6bde3f8 commit 6902603d719c6aa2bc630b1f8cb40827d70d992f
Showing with 220 additions and 33 deletions.
  1. +220 −33 mapogr.cpp
View
@@ -1359,6 +1359,180 @@ static void msOGRSplitFilter(layerObj *layer,
}
}
+/************************************************************************/
+/* msOGREscapeSQLParam */
+/************************************************************************/
+static char *msOGREscapeSQLParam(layerObj *layer, const char *pszString)
+{
+#ifdef USE_OGR
+ char* pszEscapedStr =NULL;
+ if(layer && pszString && strlen(pszString) > 0) {
+ char* pszEscapedOGRStr = CPLEscapeString(pszString, strlen(pszString),
+ CPLES_SQL );
+ pszEscapedStr = msStrdup(pszEscapedOGRStr);
+ CPLFree(pszEscapedOGRStr);
+ }
+ return pszEscapedStr;
+#else
+ /* ------------------------------------------------------------------
+ * OGR Support not included...
+ * ------------------------------------------------------------------ */
+
+ msSetError(MS_MISCERR, "OGR support is not available.",
+ "msOGREscapeSQLParam()");
+ return NULL;
+
+#endif /* USE_OGR */
+}
+
+/**********************************************************************
+ * msOGRTranslateMsExpressionToOGRSQL()
+ *
+ * Tries to translate a mapserver expression to OGR SQL, and also
+ * try to extract spatial filter
+ **********************************************************************/
+static char* msOGRTranslateMsExpressionToOGRSQL(layerObj* layer,
+ expressionObj* psFilter,
+ rectObj* psRect)
+{
+ char* msSQLExpression = NULL;
+ rectObj sBBOX;
+ int sBBOXValid = MS_FALSE;
+ tokenListNodeObjPtr node = NULL;
+ char *stresc = NULL;
+ char *snippet = NULL;
+ const char* strtmpl = NULL;
+ int bIsIntersectRectangle = MS_FALSE;
+
+ node = psFilter->tokens;
+ while (node != NULL) {
+
+ switch(node->token) {
+
+ /* literal tokens */
+
+ case MS_TOKEN_LITERAL_NUMBER:
+ snippet = (char *) msSmallMalloc(strlen(strtmpl) + 16);
+ sprintf(snippet, "%lf", node->tokenval.dblval);
+ msSQLExpression = msStringConcatenate(msSQLExpression, snippet);
+ msFree(snippet);
+ break;
+ case MS_TOKEN_LITERAL_STRING:
+ stresc = msOGREscapeSQLParam(layer, node->tokenval.strval);
+ snippet = (char *) msSmallMalloc(strlen(strtmpl) + strlen(stresc));
+ sprintf(snippet, "'%s'", stresc);
+ msSQLExpression = msStringConcatenate(msSQLExpression, snippet);
+ msFree(snippet);
+ msFree(stresc);
+ break;
+
+ case MS_TOKEN_BINDING_DOUBLE:
+ case MS_TOKEN_BINDING_INTEGER:
+ case MS_TOKEN_BINDING_STRING:
+ if(node->token == MS_TOKEN_BINDING_STRING || node->next->token == MS_TOKEN_COMPARISON_RE || node->next->token == MS_TOKEN_COMPARISON_IRE)
+ strtmpl = "CAST(%s AS CHARACTER)"; /* explicit cast necessary for certain operators */
+ else
+ strtmpl = "%s";
+ stresc = msLayerEscapePropertyName(layer, node->tokenval.bindval.item);
+ snippet = (char *) msSmallMalloc(strlen(strtmpl) + strlen(stresc));
+ sprintf(snippet, strtmpl, stresc);
+ msSQLExpression = msStringConcatenate(msSQLExpression, snippet);
+ msFree(snippet);
+ msFree(stresc);
+ break;
+
+ /* spatial comparison tokens */
+ case MS_TOKEN_COMPARISON_INTERSECTS:
+ {
+ shapeObj* shape;
+ if(node->next->token != '(') goto cleanup;
+ if(node->next->next->token != MS_TOKEN_BINDING_SHAPE) goto cleanup;
+ if(node->next->next->next->token != ',' ) goto cleanup;
+ if(node->next->next->next->next->token != MS_TOKEN_LITERAL_SHAPE ) goto cleanup;
+ if(node->next->next->next->next->next->token != ')' ) goto cleanup;
+ if(node->next->next->next->next->next->next->token != MS_TOKEN_COMPARISON_EQ ) goto cleanup;
+ if(node->next->next->next->next->next->next->next->token != MS_TOKEN_LITERAL_BOOLEAN ) goto cleanup;
+ if(node->next->next->next->next->next->next->next->tokenval.dblval != MS_TRUE) goto cleanup;
+
+ shape = node->next->next->next->next->tokenval.shpval;
+ memcpy(&sBBOX, &(shape->bounds), sizeof(rectObj));
+ sBBOXValid = TRUE;
+
+ if( shape->type == MS_SHAPE_POLYGON &&
+ shape->numlines == 1 &&
+ shape->line[0].numpoints == 5 )
+ {
+ if( shape->line[0].point[0].x == shape->line[0].point[1].x &&
+ shape->line[0].point[0].y == shape->line[0].point[3].y &&
+ shape->line[0].point[2].x == shape->line[0].point[3].x &&
+ shape->line[0].point[1].y == shape->line[0].point[2].y &&
+ shape->line[0].point[0].x == shape->line[0].point[4].x &&
+ shape->line[0].point[0].y == shape->line[0].point[4].y )
+ {
+ bIsIntersectRectangle = MS_TRUE;
+ }
+ }
+
+ node = node->next->next->next->next->next->next->next;
+ if( node && node->next && node->next->token == MS_TOKEN_LOGICAL_AND )
+ node = node->next;
+
+ break;
+ }
+
+ case MS_TOKEN_COMPARISON_EQ:
+ case MS_TOKEN_COMPARISON_NE:
+ case MS_TOKEN_COMPARISON_GT:
+ case MS_TOKEN_COMPARISON_GE:
+ case MS_TOKEN_COMPARISON_LT:
+ case MS_TOKEN_COMPARISON_LE:
+ case MS_TOKEN_LOGICAL_AND:
+ case MS_TOKEN_LOGICAL_NOT:
+ case MS_TOKEN_LOGICAL_OR:
+ case '(':
+ case ')':
+ if( node->token == MS_TOKEN_LOGICAL_AND && node->next &&
+ node->next->token == MS_TOKEN_COMPARISON_INTERSECTS )
+ node = node->next;
+ else
+ msSQLExpression = msStringConcatenate(msSQLExpression, msExpressionTokenToString(node->token));
+ break;
+
+ default:
+ goto cleanup;
+ break;
+ }
+
+ node = node->next;
+ }
+
+ if( !sBBOXValid || bIsIntersectRectangle )
+ {
+ /* We can translate completely the filter as a OGR expression, */
+ /* so no need for msEvalExpression() to do more work */
+
+ if (layer->debug >= MS_DEBUGLEVEL_VVV)
+ msDebug("msOGRTranslateMsExpressionToOGRSQL: filter can be evaluated completely on OGR side\n");
+ msFree( layer->filter.string );
+ layer->filter.string = NULL;
+ }
+
+ if( sBBOXValid )
+ {
+ psRect->minx = MS_MAX(psRect->minx, sBBOX.minx);
+ psRect->miny = MS_MAX(psRect->miny, sBBOX.miny);
+ psRect->maxx = MS_MIN(psRect->maxx, sBBOX.maxx);
+ psRect->maxy = MS_MAX(psRect->maxy, sBBOX.maxy);
+ }
+
+ return msSQLExpression;
+
+cleanup:
+ msFree(msSQLExpression);
+ return NULL;
+}
+
+
/**********************************************************************
* msOGRFileWhichShapes()
*
@@ -1465,6 +1639,41 @@ static int msOGRFileWhichShapes(layerObj *layer, rectObj rect,
msFree(pszLayerDef);
}
+
+ /* ------------------------------------------------------------------
+ * If there's a mapserver filter, tries to parse it as a mapserver expression
+ * (for example if request coming from WFS), and then tries to translate
+ * the mapserver expression as OGR SQL.
+ * ------------------------------------------------------------------ */
+ if( pszMSFilter != NULL ) {
+ expressionObj filter;
+ msInitExpression(&filter);
+ filter.string = msStrdup(pszMSFilter);
+ filter.type = MS_EXPRESSION;
+ if( msTokenizeExpression(&filter, layer->items, &(layer->numitems)) == MS_SUCCESS )
+ {
+ char* pszAdditionalOGRFilter = msOGRTranslateMsExpressionToOGRSQL(layer, &filter, &rect);
+ if( pszAdditionalOGRFilter != NULL )
+ {
+ if( pszOGRFilter != NULL )
+ {
+ char* pszTmp = msStringConcatenate(NULL, "(");
+ pszTmp = msStringConcatenate(pszTmp, pszOGRFilter);
+ pszTmp = msStringConcatenate(pszTmp, ") AND (");
+ pszTmp = msStringConcatenate(pszTmp, pszAdditionalOGRFilter);
+ pszTmp = msStringConcatenate(pszTmp, ")");
+ msFree(pszTmp);
+ msFree(pszAdditionalOGRFilter);
+ pszOGRFilter = pszTmp;
+ }
+ else
+ pszOGRFilter = pszAdditionalOGRFilter;
+ }
+ }
+ msFreeExpression(&filter);
+ }
+ msFree(pszMSFilter);
+
/* ------------------------------------------------------------------
* Set Spatial filter... this may result in no features being returned
* if layer does not overlap current view.
@@ -1525,14 +1734,13 @@ static int msOGRFileWhichShapes(layerObj *layer, rectObj rect,
* keyword in the filter string. Otherwise, ensure the attribute
* filter is clear.
* ------------------------------------------------------------------ */
-
- if( pszMSFilter != NULL ) {
- msLoadExpressionString(&layer->filter, pszMSFilter);
- if(layer->filter.type == MS_EXPRESSION) msTokenizeExpression(&(layer->filter), layer->items, &(layer->numitems));
- }
- msFree(pszMSFilter);
if( pszOGRFilter != NULL ) {
+
+ if (layer->debug >= MS_DEBUGLEVEL_VVV)
+ msDebug("msOGRFileWhichShapes: Setting attribute filter to %s\n",
+ pszOGRFilter );
+
CPLErrorReset();
if( OGR_L_SetAttributeFilter( psInfo->hLayer, pszOGRFilter )
!= OGRERR_NONE ) {
@@ -3194,33 +3402,6 @@ void msOGRCleanup( void )
#endif
}
-/************************************************************************/
-/* msOGREscapeSQLParam */
-/************************************************************************/
-char *msOGREscapeSQLParam(layerObj *layer, const char *pszString)
-{
-#ifdef USE_OGR
- char* pszEscapedStr =NULL;
- if(layer && pszString && strlen(pszString) > 0) {
- char* pszEscapedOGRStr = CPLEscapeString(pszString, strlen(pszString),
- CPLES_SQL );
- pszEscapedStr = msStrdup(pszEscapedOGRStr);
- CPLFree(pszEscapedOGRStr);
- }
- return pszEscapedStr;
-#else
- /* ------------------------------------------------------------------
- * OGR Support not included...
- * ------------------------------------------------------------------ */
-
- msSetError(MS_MISCERR, "OGR support is not available.",
- "msOGREscapeSQLParam()");
- return NULL;
-
-#endif /* USE_OGR */
-}
-
-
/************************************************************************/
/* msOGREscapeSQLParam */
/************************************************************************/
@@ -3251,6 +3432,11 @@ char *msOGREscapePropertyName(layerObj *layer, const char *pszString)
#endif /* USE_OGR */
}
+static int msOGRLayerSupportsCommonFilters(layerObj *layer)
+{
+ return MS_TRUE;
+}
+
/************************************************************************/
/* msOGRLayerInitializeVirtualTable() */
/************************************************************************/
@@ -3261,6 +3447,7 @@ int msOGRLayerInitializeVirtualTable(layerObj *layer)
/* layer->vtable->LayerTranslateFilter, use default */
+ layer->vtable->LayerSupportsCommonFilters = msOGRLayerSupportsCommonFilters;
layer->vtable->LayerInitItemInfo = msOGRLayerInitItemInfo;
layer->vtable->LayerFreeItemInfo = msOGRLayerFreeItemInfo;
layer->vtable->LayerOpen = msOGRLayerOpenVT;

0 comments on commit 6902603

Please sign in to comment.