Skip to content
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
@@ -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.
You can’t perform that action at this time.