Skip to content

Commit

Permalink
Whoops, forgot all about the query changes (new method) resulting fro…
Browse files Browse the repository at this point in the history
…m RFC 64. This change merges those and introduces the queryByFilter() method to SWIG-based MapScript. (#3613)

git-svn-id: http://svn.osgeo.org/mapserver/trunk@10828 7532c77e-422f-0410-93f4-f0b67bdd69e2
  • Loading branch information
sdlime committed Jan 3, 2011
1 parent 70e32f0 commit 2d3356f
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 2 deletions.
171 changes: 171 additions & 0 deletions mapquery.c
Expand Up @@ -55,6 +55,7 @@ int msInitQuery(queryObj *query)
query->op = -1;

query->item = query->str = NULL;
query->filter = NULL;

return MS_SUCCESS;
}
Expand All @@ -68,6 +69,10 @@ void msFreeQuery(queryObj *query)

if(query->item) free(query->item);
if(query->str) free(query->str);
if(query->filter) {
freeExpression(query->filter);
free(query->filter);
}
}

/*
Expand All @@ -93,6 +98,9 @@ int msExecuteQuery(mapObj *map)
case MS_QUERY_BY_ATTRIBUTE:
status = msQueryByAttributes(map);
break;
case MS_QUERY_BY_FILTER:
status = msQueryByFilter(map);
break;
case MS_QUERY_BY_OPERATOR:
status = msQueryByOperator(map);
break;
Expand Down Expand Up @@ -685,6 +693,169 @@ int msQueryByAttributes(mapObj *map)
return(MS_FAILURE);
}

/*
** Query using common expression syntax.
*/
int msQueryByFilter(mapObj *map)
{
int l;
int start, stop=0;

layerObj *lp;

char status;

expressionObj old_filter;

rectObj search_rect;

shapeObj shape;

int nclasses = 0;
int *classgroup = NULL;

if(map->query.type != MS_QUERY_BY_FILTER) {
msSetError(MS_QUERYERR, "The query is not properly defined.", "msQueryByFilter()");
return(MS_FAILURE);
}
if(!map->query.filter) { // TODO: check filter type too
msSetError(MS_QUERYERR, "Filter is not set.", "msQueryByFilter()");
return(MS_FAILURE);
}

msInitShape(&shape);

if(map->query.layer < 0 || map->query.layer >= map->numlayers)
start = map->numlayers-1;
else
start = stop = map->query.layer;

for(l=start; l>=stop; l--) {
lp = (GET_LAYER(map, l));

/* conditions may have changed since this layer last drawn, so set
layer->project true to recheck projection needs (Bug #673) */
lp->project = MS_TRUE;

/* free any previous search results, do it now in case one of the next few tests fail */
if(lp->resultcache) {
if(lp->resultcache->results) free(lp->resultcache->results);
free(lp->resultcache);
lp->resultcache = NULL;
}

if(!msIsLayerQueryable(lp)) continue;
if(lp->status == MS_OFF) continue;
if(lp->type == MS_LAYER_RASTER) continue; /* ok to skip? */

if(map->scaledenom > 0) {
if((lp->maxscaledenom > 0) && (map->scaledenom > lp->maxscaledenom)) continue;
if((lp->minscaledenom > 0) && (map->scaledenom <= lp->minscaledenom)) continue;
}

if (lp->maxscaledenom <= 0 && lp->minscaledenom <= 0) {
if((lp->maxgeowidth > 0) && ((map->extent.maxx - map->extent.minx) > lp->maxgeowidth)) continue;
if((lp->mingeowidth > 0) && ((map->extent.maxx - map->extent.minx) < lp->mingeowidth)) continue;
}

initExpression(&old_filter);
msCopyExpression(&old_filter, &lp->filter); /* save existing filter */
if(msLayerSupportsCommonFilters(lp)) {
msCopyExpression(&lp->filter, map->query.filter); /* apply new filter */
}

status = msLayerOpen(lp);
if(status != MS_SUCCESS) goto query_error;

/* build item list, we want *all* items */
status = msLayerWhichItems(lp, MS_TRUE, NULL);
if(status != MS_SUCCESS) goto query_error;

if(!msLayerSupportsCommonFilters(lp)) {
freeExpression(&lp->filter); /* clear existing filter */
status = msTokenizeExpression(map->query.filter, lp->items, &(lp->numitems));
if(status != MS_SUCCESS) goto query_error;
}

search_rect = map->query.rect;
#ifdef USE_PROJ
if(lp->project && msProjectionsDiffer(&(lp->projection), &(map->projection)))
msProjectRect(&(map->projection), &(lp->projection), &search_rect); /* project the searchrect to source coords */
else
lp->project = MS_FALSE;
#endif

status = msLayerWhichShapes(lp, search_rect);
if(status == MS_DONE) { /* no overlap */
msLayerClose(lp);
continue;
} else if(status != MS_SUCCESS) goto query_error;

lp->resultcache = (resultCacheObj *)malloc(sizeof(resultCacheObj)); /* allocate and initialize the result cache */
initResultCache( lp->resultcache);

nclasses = 0;
classgroup = NULL;
if (lp->classgroup && lp->numclasses > 0)
classgroup = msAllocateValidClassGroups(lp, &nclasses);

while((status = msLayerNextShape(lp, &shape)) == MS_SUCCESS) { /* step through the shapes */

if(!msLayerSupportsCommonFilters(lp)) { /* we have to apply the filter here instead of within the driver */
if(msEvalExpression(lp, &shape, map->query.filter, -1) != MS_TRUE) { /* next shape */
msFreeShape(&shape);
continue;
}
}

shape.classindex = msShapeGetClass(lp, &shape, map->scaledenom, classgroup, nclasses);
if(!(lp->template) && ((shape.classindex == -1) || (lp->class[shape.classindex]->status == MS_OFF))) { /* not a valid shape */
msFreeShape(&shape);
continue;
}

if(!(lp->template) && !(lp->class[shape.classindex]->template)) { /* no valid template */
msFreeShape(&shape);
continue;
}

#ifdef USE_PROJ
if(lp->project && msProjectionsDiffer(&(lp->projection), &(map->projection)))
msProjectShape(&(lp->projection), &(map->projection), &shape);
else
lp->project = MS_FALSE;
#endif

addResult(lp->resultcache, &shape);
msFreeShape(&shape);
} /* next shape */

if(classgroup) msFree(classgroup);

msCopyExpression(&lp->filter, &old_filter); /* restore old filter */
freeExpression(&old_filter);

if(status != MS_DONE) goto query_error;
if(lp->resultcache->numresults == 0) msLayerClose(lp); /* no need to keep the layer open */

} /* next layer */

/* was anything found? */
for(l=start; l>=stop; l--) {
if(GET_LAYER(map, l)->resultcache && GET_LAYER(map, l)->resultcache->numresults > 0)
return MS_SUCCESS;
}

msSetError(MS_NOTFOUND, "No matching record(s) found.", "msQueryByFilter()");
return MS_FAILURE;

query_error:
msCopyExpression(&lp->filter, &old_filter); /* restore old filter */
freeExpression(&old_filter);
msLayerClose(lp);
return MS_FAILURE;
}

int msQueryByRect(mapObj *map)
{
int l; /* counters */
Expand Down
6 changes: 4 additions & 2 deletions mapserver.h
Expand Up @@ -443,7 +443,7 @@ enum MS_JOIN_TYPE {MS_JOIN_ONE_TO_ONE, MS_JOIN_ONE_TO_MANY};
#define MS_MULTIPLE 1

enum MS_QUERY_MODE {MS_QUERY_SINGLE, MS_QUERY_MULTIPLE};
enum MS_QUERY_TYPE {MS_QUERY_IS_NULL, MS_QUERY_BY_POINT, MS_QUERY_BY_RECT, MS_QUERY_BY_SHAPE, MS_QUERY_BY_ATTRIBUTE, MS_QUERY_BY_INDEX, MS_QUERY_BY_OPERATOR};
enum MS_QUERY_TYPE {MS_QUERY_IS_NULL, MS_QUERY_BY_POINT, MS_QUERY_BY_RECT, MS_QUERY_BY_SHAPE, MS_QUERY_BY_ATTRIBUTE, MS_QUERY_BY_INDEX, MS_QUERY_BY_OPERATOR, MS_QUERY_BY_FILTER};

enum MS_ALIGN_VALUE {MS_ALIGN_LEFT, MS_ALIGN_CENTER, MS_ALIGN_RIGHT};

Expand Down Expand Up @@ -733,6 +733,8 @@ typedef struct {
char *item; /* by attribute */
char *str;

expressionObj *filter; /* by filter */

int op; /* by GEOS operator */

int slayer; /* selection layer, used for msQueryByFeatures() (note this is not a query mode per se) */
Expand Down Expand Up @@ -1682,8 +1684,8 @@ MS_DLL_EXPORT int loadExpressionString(expressionObj *exp, char *value);
/* Use this next, thread safe wrapper, function everywhere else */
MS_DLL_EXPORT int msLoadExpressionString(expressionObj *exp, char *value);
MS_DLL_EXPORT char *msGetExpressionString(expressionObj *exp);
MS_DLL_EXPORT void initExpression(expressionObj *exp);
MS_DLL_EXPORT void freeExpression(expressionObj *exp);
MS_DLL_EXPORT char *msGetExpressionString(expressionObj *exp);

MS_DLL_EXPORT void msLayerSubstituteString(layerObj *layer, const char *from, const char *to);
MS_DLL_EXPORT void msApplyDefaultSubstitutions(mapObj *map);
Expand Down

0 comments on commit 2d3356f

Please sign in to comment.