Skip to content

Commit

Permalink
WFS 2.0: implement stored queries; also fix maximum feature count sup…
Browse files Browse the repository at this point in the history
…port for GetFeature involving filters or featureid
  • Loading branch information
rouault committed Nov 6, 2013
1 parent fb393d6 commit 68be3a0
Show file tree
Hide file tree
Showing 16 changed files with 1,637 additions and 565 deletions.
2 changes: 2 additions & 0 deletions mapgml.c
Expand Up @@ -1184,6 +1184,8 @@ static void msGMLWriteGroup(FILE *stream, gmlGroupObj *group, shapeObj *shape, g
else
msIO_fprintf(stream, "%s</%s>\n", tab, group->name);

msFree(itemtab);

return;
}
#endif
Expand Down
113 changes: 75 additions & 38 deletions mapogcfilter.c
Expand Up @@ -42,7 +42,7 @@



int FLTIsNumeric(char *pszValue)
int FLTIsNumeric(const char *pszValue)
{
if (pszValue != NULL && *pszValue != '\0' && !isspace(*pszValue)) {
/*the regex seems to have a problem on windows when mapserver is built using
Expand Down Expand Up @@ -78,7 +78,7 @@ int FLTIsNumeric(char *pszValue)
** Apply an expression to the layer's filter element.
**
*/
int FLTApplyExpressionToLayer(layerObj *lp, char *pszExpression)
int FLTApplyExpressionToLayer(layerObj *lp, const char *pszExpression)
{
char *pszFinalExpression=NULL, *pszBuffer = NULL;
/*char *escapedTextString=NULL;*/
Expand Down Expand Up @@ -143,7 +143,7 @@ int FLTApplyExpressionToLayer(layerObj *lp, char *pszExpression)
return MS_FALSE;
}

char *FLTGetExpressionForValuesRanges(layerObj *lp, char *item, char *value, int forcecharcter)
char *FLTGetExpressionForValuesRanges(layerObj *lp, const char *item, const char *value, int forcecharcter)
{
int bIscharacter, bSqlLayer;
char *pszExpression = NULL, *pszEscapedStr=NULL, *pszTmpExpression=NULL;
Expand Down Expand Up @@ -665,7 +665,7 @@ int FLTLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, mapObj *map,
/* Calling function should use FreeFilterEncodingNode function */
/* to free memeory. */
/************************************************************************/
FilterEncodingNode *FLTParseFilterEncoding(char *szXMLString)
FilterEncodingNode *FLTParseFilterEncoding(const char *szXMLString)
{
CPLXMLNode *psRoot = NULL, *psChild=NULL, *psFilter=NULL;
FilterEncodingNode *psFilterNode = NULL;
Expand Down Expand Up @@ -947,8 +947,6 @@ void FLTInsertElementInNode(FilterEncodingNode *psFilterNode,
CPLXMLNode *psFeatureIdNode = NULL;
const char *pszFeatureId=NULL;
char *pszFeatureIdList=NULL;
char **tokens = NULL;
int nTokens = 0;

if (psFilterNode && psXMLNode && psXMLNode->pszValue) {
psFilterNode->pszValue = msStrdup(psXMLNode->pszValue);
Expand Down Expand Up @@ -1455,15 +1453,7 @@ void FLTInsertElementInNode(FilterEncodingNode *psFilterNode,
if (pszFeatureIdList)
pszFeatureIdList = msStringConcatenate(pszFeatureIdList, ",");

/*typname could be part of the value : INWATERA_1M.1234*/
tokens = msStringSplit(pszFeatureId,'.', &nTokens);
if (tokens && nTokens == 2)
pszFeatureIdList = msStringConcatenate(pszFeatureIdList, tokens[1]);
else
pszFeatureIdList = msStringConcatenate(pszFeatureIdList, pszFeatureId);

if (tokens)
msFreeCharArray(tokens, nTokens);
pszFeatureIdList = msStringConcatenate(pszFeatureIdList, pszFeatureId);
}
psFeatureIdNode = psFeatureIdNode->psNext;
}
Expand Down Expand Up @@ -1863,7 +1853,6 @@ char *FLTGetMapserverExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
char szTmp[256];
char **tokens = NULL;
int nTokens = 0, i=0,bString=0;
char *pszTmp;

if (!psFilterNode)
return NULL;
Expand Down Expand Up @@ -1897,15 +1886,18 @@ char *FLTGetMapserverExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
tokens = msStringSplit(psFilterNode->pszValue,',', &nTokens);
if (tokens && nTokens > 0) {
for (i=0; i<nTokens; i++) {
const char* pszId = tokens[i];
const char* pszDot = strchr(pszId, '.');
if( pszDot )
pszId = pszDot + 1;
if (i == 0) {
pszTmp = tokens[0];
if(FLTIsNumeric(pszTmp) == MS_FALSE)
if(FLTIsNumeric(pszId) == MS_FALSE)
bString = 1;
}
if (bString)
snprintf(szTmp, sizeof(szTmp), "('[%s]' = '%s')" , pszAttribute, tokens[i]);
snprintf(szTmp, sizeof(szTmp), "('[%s]' = '%s')" , pszAttribute, pszId);
else
snprintf(szTmp, sizeof(szTmp), "([%s] = %s)" , pszAttribute, tokens[i]);
snprintf(szTmp, sizeof(szTmp), "([%s] = %s)" , pszAttribute, pszId);

if (pszExpression != NULL)
pszExpression = msStringConcatenate(pszExpression, " OR ");
Expand Down Expand Up @@ -1989,13 +1981,18 @@ char *FLTGetSQLExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
if (tokens && nTokens > 0) {
for (i=0; i<nTokens; i++) {
char *pszEscapedStr = NULL;
if (strlen(tokens[i]) <= 0)
const char* pszId = tokens[i];
const char* pszDot = strchr(pszId, '.');
if( pszDot )
pszId = pszDot + 1;

if (strlen(pszId) <= 0)
continue;

if (FLTIsNumeric((tokens[i])) == MS_FALSE)
if (FLTIsNumeric(pszId) == MS_FALSE)
bString = 1;

pszEscapedStr = msLayerEscapeSQLParam(lp, tokens[i]);
pszEscapedStr = msLayerEscapeSQLParam(lp, pszId);
if (bString)
snprintf(szTmp, sizeof(szTmp), "(%s = '%s')" , pszAttribute, pszEscapedStr);
else
Expand Down Expand Up @@ -2950,21 +2947,11 @@ int FLTHasSpatialFilter(FilterEncodingNode *psNode)
FilterEncodingNode *FLTCreateFeatureIdFilterEncoding(char *pszString)
{
FilterEncodingNode *psFilterNode = NULL;
char **tokens = NULL;
int nTokens = 0;

if (pszString) {
psFilterNode = FLTCreateFilterEncodingNode();
psFilterNode->eType = FILTER_NODE_TYPE_FEATUREID;
/*split if tyname is included in the string*/
tokens = msStringSplit(pszString,'.', &nTokens);
if (tokens && nTokens == 2)
psFilterNode->pszValue = msStrdup(tokens[1]);
else
psFilterNode->pszValue = msStrdup(pszString);

if (tokens)
msFreeCharArray(tokens, nTokens);
psFilterNode->pszValue = msStrdup(pszString);
return psFilterNode;
}
return NULL;
Expand Down Expand Up @@ -3267,12 +3254,12 @@ static void FLTRemoveGroupName(FilterEncodingNode *psFilterNode,
}

/************************************************************************/
/* FLTPreParseFilterForAlias */
/* FLTPreParseFilterForAliasAndGroup */
/* */
/* Utility function to replace aliased' attributes with their */
/* real name. */
/* Utility function to replace aliased' and grouped attributes */
/* with their internal name. */
/************************************************************************/
void FLTPreParseFilterForAlias(FilterEncodingNode *psFilterNode,
void FLTPreParseFilterForAliasAndGroup(FilterEncodingNode *psFilterNode,
mapObj *map, int i, const char *namespaces)
{
layerObj *lp=NULL;
Expand Down Expand Up @@ -3317,6 +3304,56 @@ void FLTPreParseFilterForAlias(FilterEncodingNode *psFilterNode,
#endif
}

/************************************************************************/
/* FLTCheckFeatureIdFilters */
/* */
/* Check that FeatureId filters match features in the active */
/* layer. */
/************************************************************************/
int FLTCheckFeatureIdFilters(FilterEncodingNode *psFilterNode,
mapObj *map, int i)
{
int status = MS_SUCCESS;

if (psFilterNode->eType == FILTER_NODE_TYPE_FEATUREID)
{
char** tokens;
int nTokens = 0;
layerObj* lp;
int j;

lp = GET_LAYER(map, i);
tokens = msStringSplit(psFilterNode->pszValue,',', &nTokens);
for (j=0; j<nTokens; j++) {
const char* pszId = tokens[j];
const char* pszDot = strchr(pszId, '.');
if( pszDot )
{
if( pszDot - pszId != strlen(lp->name) ||
strncasecmp(pszId, lp->name, strlen(lp->name)) != 0 )
{
msSetError(MS_MISCERR, "Feature id %s not consistant with feature type name %s.",
"FLTPreParseFilterForAlias()", pszId, lp->name);
status = MS_FAILURE;
break;
}
}
}
msFreeCharArray(tokens, nTokens);
}

if (psFilterNode->psLeftNode)
{
status = FLTCheckFeatureIdFilters(psFilterNode->psLeftNode, map, i);
if( status == MS_SUCCESS )
{
if (psFilterNode->psRightNode)
status = FLTCheckFeatureIdFilters(psFilterNode->psRightNode, map, i);
}
}
return status;
}


#ifdef USE_LIBXML2

Expand Down
14 changes: 8 additions & 6 deletions mapogcfilter.h
Expand Up @@ -32,9 +32,9 @@
#include "mapserver.h"

/*dont need ogr for these functikons*/
MS_DLL_EXPORT int FLTIsNumeric(char *pszValue);
MS_DLL_EXPORT int FLTApplyExpressionToLayer(layerObj *lp, char *pszExpression);
MS_DLL_EXPORT char *FLTGetExpressionForValuesRanges(layerObj *lp, char *item, char *value, int forcecharcter);
MS_DLL_EXPORT int FLTIsNumeric(const char *pszValue);
MS_DLL_EXPORT int FLTApplyExpressionToLayer(layerObj *lp, const char *pszExpression);
MS_DLL_EXPORT char *FLTGetExpressionForValuesRanges(layerObj *lp, const char *item, const char *value, int forcecharcter);

#ifdef USE_OGR

Expand All @@ -58,7 +58,7 @@ typedef struct {
/* -------------------------------------------------------------------- */
/* prototypes. */
/* -------------------------------------------------------------------- */
MS_DLL_EXPORT FilterEncodingNode *FLTParseFilterEncoding(char *szXMLString);
MS_DLL_EXPORT FilterEncodingNode *FLTParseFilterEncoding(const char *szXMLString);
MS_DLL_EXPORT FilterEncodingNode *FLTCreateFilterEncodingNode(void);
MS_DLL_EXPORT int FLTApplyFilterToLayer(FilterEncodingNode *psNode, mapObj *map,
int iLayerIndex);
Expand Down Expand Up @@ -137,8 +137,10 @@ MS_DLL_EXPORT xmlNodePtr FLTGetCapabilities(xmlNsPtr psNsParent, xmlNsPtr psNsOg

void FLTDoAxisSwappingIfNecessary(FilterEncodingNode *psFilterNode, int bDefaultSRSNeedsAxisSwapping);

void FLTPreParseFilterForAlias(FilterEncodingNode *psFilterNode,
mapObj *map, int i, const char *namespaces);
void FLTPreParseFilterForAliasAndGroup(FilterEncodingNode *psFilterNode,
mapObj *map, int i, const char *namespaces);
int FLTCheckFeatureIdFilters(FilterEncodingNode *psFilterNode,
mapObj *map, int i);

#endif

Expand Down
23 changes: 18 additions & 5 deletions mapogcfiltercommon.c
Expand Up @@ -565,21 +565,25 @@ char *FLTGetFeatureIdCommonExpression(FilterEncodingNode *psFilterNode, layerObj
for (i=0; i<nTokens; i++) {
char *pszTmp = NULL;
int bufferSize = 0;
const char* pszId = tokens[i];
const char* pszDot = strchr(pszId, '.');
if( pszDot )
pszId = pszDot + 1;

if (i == 0) {
if(FLTIsNumeric(tokens[0]) == MS_FALSE)
if(FLTIsNumeric(pszId) == MS_FALSE)
bString = 1;
}


if (bString) {
bufferSize = 11+strlen(tokens[i])+strlen(pszAttribute)+1;
bufferSize = 11+strlen(pszId)+strlen(pszAttribute)+1;
pszTmp = (char *)msSmallMalloc(bufferSize);
snprintf(pszTmp, bufferSize, "(\"[%s]\" ==\"%s\")" , pszAttribute, tokens[i]);
snprintf(pszTmp, bufferSize, "(\"[%s]\" ==\"%s\")" , pszAttribute, pszId);
} else {
bufferSize = 8+strlen(tokens[i])+strlen(pszAttribute)+1;
bufferSize = 8+strlen(pszId)+strlen(pszAttribute)+1;
pszTmp = (char *)msSmallMalloc(bufferSize);
snprintf(pszTmp, bufferSize, "([%s] == %s)" , pszAttribute, tokens[i]);
snprintf(pszTmp, bufferSize, "([%s] == %s)" , pszAttribute, pszId);
}

if (pszExpression != NULL)
Expand Down Expand Up @@ -636,8 +640,17 @@ char *FLTGetCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
int FLTApplyFilterToLayerCommonExpression(mapObj *map, int iLayerIndex, char *pszExpression)
{
int retval;
int save_startindex;
int save_maxfeatures;
int save_only_cache_result_count;

save_startindex = map->query.startindex;
save_maxfeatures = map->query.maxfeatures;
save_only_cache_result_count = map->query.only_cache_result_count;
msInitQuery(&(map->query));
map->query.startindex = save_startindex;
map->query.maxfeatures = save_maxfeatures;
map->query.only_cache_result_count = save_only_cache_result_count;

map->query.type = MS_QUERY_BY_FILTER;

Expand Down
2 changes: 1 addition & 1 deletion mapogcsld.c
Expand Up @@ -837,7 +837,7 @@ int msSLDParseNamedLayer(CPLXMLNode *psRoot, layerObj *psLayer)
msInsertHashTable(&psLayer->metadata, key,
msLookupHashTable(&psCurrentLayer->metadata, key));
}
FLTPreParseFilterForAlias(psNode, psLayer->map, j, "G");
FLTPreParseFilterForAliasAndGroup(psNode, psLayer->map, j, "G");
}

pszExpression = FLTGetCommonExpression(psNode, psLayer);
Expand Down
7 changes: 2 additions & 5 deletions mapogcsos.c
Expand Up @@ -80,7 +80,6 @@ static int msSOSException(mapObj *map, char *locator, char *exceptionCode)
{
int size = 0;
char *errorString = NULL;
char *errorMessage = NULL;
char *schemasLocation = NULL;

xmlDocPtr psDoc = NULL;
Expand All @@ -91,12 +90,11 @@ static int msSOSException(mapObj *map, char *locator, char *exceptionCode)
psNsOws = xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/ows/1.1", BAD_CAST "ows");

errorString = msGetErrorString("\n");
errorMessage = msEncodeHTMLEntities(errorString);
schemasLocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));

psDoc = xmlNewDoc(BAD_CAST "1.0");

psRootNode = msOWSCommonExceptionReport(psNsOws, OWS_1_1_0, schemasLocation, pszSOSVersion, msOWSGetLanguage(map, "exception"), exceptionCode, locator, errorMessage);
psRootNode = msOWSCommonExceptionReport(psNsOws, OWS_1_1_0, schemasLocation, pszSOSVersion, msOWSGetLanguage(map, "exception"), exceptionCode, locator, errorString);

xmlDocSetRootElement(psDoc, psRootNode);

Expand All @@ -111,7 +109,6 @@ static int msSOSException(mapObj *map, char *locator, char *exceptionCode)

/*free buffer and the document */
free(errorString);
free(errorMessage);
free(schemasLocation);
xmlFree(buffer);
xmlFreeDoc(psDoc);
Expand Down Expand Up @@ -2173,7 +2170,7 @@ this request. Check sos/ows_enable_request settings.", "msSOSGetObservation()",
lp = GET_LAYER(map, i);
if (lp->status == MS_ON) {
/* preparse parser so that alias for fields can be used */
FLTPreParseFilterForAlias(psFilterNode, map, i, "S");
FLTPreParseFilterForAliasAndGroup(psFilterNode, map, i, "S");
/* validate that the property names used are valid
(there is a corresponding layer attribute) */
if (msLayerOpen(lp) == MS_SUCCESS && msLayerGetItems(lp) == MS_SUCCESS) {
Expand Down
13 changes: 12 additions & 1 deletion mapows.h
Expand Up @@ -64,8 +64,11 @@ typedef struct {
char *pszAcceptVersions;
char *pszSections;
char *pszSortBy; /* Not implemented yet */
char *pszLanguage;
char *pszLanguage; /* Inspire extension */
char *pszValueReference; /* For GetValueReference */
char *pszStoredQueryId; /* For DescribeStoredQueries */
int countGetFeatureById; /* Number of urn:ogc:def:query:OGC-WFS::GetFeatureById GetFeature requests */
int bHasPostStoredQuery; /* TRUE if a XML GetFeature StoredQuery is present */
} wfsParamsObj;

/*
Expand Down Expand Up @@ -477,6 +480,14 @@ int msWFSException20(mapObj *map, const char *locator,
const char *exceptionCode);
int msWFSGetCapabilities20(mapObj *map, wfsParamsObj *params,
cgiRequestObj *req, owsRequestObj *ows_request);
int msWFSListStoredQueries20(mapObj *map, wfsParamsObj *params,
cgiRequestObj *req, owsRequestObj *ows_request);
int msWFSDescribeStoredQueries20(mapObj *map, wfsParamsObj *params,
cgiRequestObj *req, owsRequestObj *ows_request);
char* msWFSGetResolvedStoredQuery20(mapObj *map,
wfsParamsObj *wfsparams,
const char* id,
hashTableObj* hashTable);

#endif

Expand Down
4 changes: 3 additions & 1 deletion mapowscommon.c
Expand Up @@ -489,7 +489,9 @@ xmlNodePtr msOWSCommonExceptionReport(xmlNsPtr psNsOws, int ows_version, const c
}

if (ExceptionText != NULL) {
xmlNewChild(psMainNode, NULL, BAD_CAST "ExceptionText", BAD_CAST ExceptionText);
char* errorMessage = msEncodeHTMLEntities(ExceptionText);
xmlNewChild(psMainNode, NULL, BAD_CAST "ExceptionText", BAD_CAST errorMessage);
msFree(errorMessage);
}

free(xsi_schemaLocation);
Expand Down

0 comments on commit 68be3a0

Please sign in to comment.