Skip to content

Commit

Permalink
WFS: implements SortBy
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Nov 13, 2013
1 parent 8131096 commit df08e5b
Show file tree
Hide file tree
Showing 8 changed files with 520 additions and 240 deletions.
7 changes: 7 additions & 0 deletions mapfile.c
Expand Up @@ -3805,6 +3805,9 @@ int initLayer(layerObj *layer, mapObj *map)
layer->utfitemindex = -1;

layer->encoding = NULL;

layer->sortBy.nProperties = 0;
layer->sortBy.properties = NULL;

return(0);
}
Expand Down Expand Up @@ -3923,6 +3926,10 @@ int freeLayer(layerObj *layer)

freeExpression(&(layer->utfdata));
msFree(layer->utfitem);

for(i=0;i<layer->sortBy.nProperties;i++)
msFree(layer->sortBy.properties[i].item);
msFree(layer->sortBy.properties);

return MS_SUCCESS;
}
Expand Down
60 changes: 60 additions & 0 deletions maplayer.c
Expand Up @@ -1412,6 +1412,66 @@ int msLayerSupportsPaging(layerObj *layer)
return MS_FALSE;
}

/*
* msLayerSupportsSorting()
*
* Returns MS_TRUE if the layer supports sorting/ordering.
*/
int msLayerSupportsSorting(layerObj *layer)
{
if (layer &&
((layer->connectiontype == MS_OGR) ||
(layer->connectiontype == MS_POSTGIS)) )
return MS_TRUE;

return MS_FALSE;
}

/*
* msLayerSetSort()
*
* Copy the sortBy clause passed as an argument into the layer sortBy member.
*/
void msLayerSetSort(layerObj *layer, const sortByClause* sortBy)
{
int i;
for(i=0;i<layer->sortBy.nProperties;i++)
msFree(layer->sortBy.properties[i].item);
msFree(layer->sortBy.properties);

layer->sortBy.nProperties = sortBy->nProperties;
layer->sortBy.properties = (sortByProperties*) msSmallMalloc(
sortBy->nProperties * sizeof(sortByProperties) );
for(i=0;i<layer->sortBy.nProperties;i++) {
layer->sortBy.properties[i].item = msStrdup(sortBy->properties[i].item);
layer->sortBy.properties[i].sortOrder = sortBy->properties[i].sortOrder;
}
}

/*
* msLayerBuildSQLOrderBy()
*
* Returns the content of a SQL ORDER BY clause from the sortBy member of
* the layer. The string does not contain the "ORDER BY" keywords itself.
*/
char* msLayerBuildSQLOrderBy(layerObj *layer)
{
char* strOrderBy = NULL;
if( layer->sortBy.nProperties > 0 ) {
int i;
for(i=0;i<layer->sortBy.nProperties;i++) {
char* escaped = msLayerEscapePropertyName(layer, layer->sortBy.properties[i].item);
if( i > 0 )
strOrderBy = msStringConcatenate(strOrderBy, ", ");
strOrderBy = msStringConcatenate(strOrderBy, escaped);
if( layer->sortBy.properties[i].sortOrder == SORT_DESC )
strOrderBy = msStringConcatenate(strOrderBy, " DESC");
msFree(escaped);
}
}
return strOrderBy;
}

int
msLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, mapObj *map,
int iLayerIndex)
Expand Down
52 changes: 50 additions & 2 deletions mapogr.cpp
Expand Up @@ -51,6 +51,7 @@

typedef struct ms_ogr_file_info_t {
char *pszFname;
char *pszLayerDef;
int nLayerIndex;
OGRDataSourceH hDS;
OGRLayerH hLayer;
Expand Down Expand Up @@ -1196,14 +1197,13 @@ msOGRFileOpen(layerObj *layer, const char *connection )
return NULL;
}

CPLFree( pszLayerDef );

/* ------------------------------------------------------------------
* OK... open succeded... alloc and fill msOGRFileInfo inside layer obj
* ------------------------------------------------------------------ */
msOGRFileInfo *psInfo =(msOGRFileInfo*)CPLCalloc(1,sizeof(msOGRFileInfo));

psInfo->pszFname = CPLStrdup(OGR_DS_GetName( hDS ));
psInfo->pszLayerDef = pszLayerDef;
psInfo->nLayerIndex = nLayerIndex;
psInfo->hDS = hDS;
psInfo->hLayer = hLayer;
Expand Down Expand Up @@ -1247,6 +1247,7 @@ static int msOGRFileClose(layerObj *layer, msOGRFileInfo *psInfo )
psInfo->pszFname, psInfo->nLayerIndex);

CPLFree(psInfo->pszFname);
CPLFree(psInfo->pszLayerDef);

ACQUIRE_OGR_LOCK;
if (psInfo->hLastFeature)
Expand Down Expand Up @@ -1361,6 +1362,53 @@ static int msOGRFileWhichShapes(layerObj *layer, rectObj rect,
return(MS_FAILURE);
}

/* Apply sortBy */
if( layer->sortBy.nProperties > 0 ) {
char* strOrderBy;
char* pszLayerDef = NULL;

strOrderBy = msLayerBuildSQLOrderBy(layer);

if( psInfo->nLayerIndex == -1 )
{
pszLayerDef = msStrdup(psInfo->pszLayerDef);
if( strcasestr(psInfo->pszLayerDef, " ORDER BY ") == NULL )
pszLayerDef = msStringConcatenate(pszLayerDef, " ORDER BY ");
else
pszLayerDef = msStringConcatenate(pszLayerDef, ", ");
}
else
{
pszLayerDef = msStringConcatenate(pszLayerDef, "SELECT * FROM \"");
pszLayerDef = msStringConcatenate(pszLayerDef, OGR_FD_GetName(OGR_L_GetLayerDefn(psInfo->hLayer)));
pszLayerDef = msStringConcatenate(pszLayerDef, "\" ORDER BY ");
}

pszLayerDef = msStringConcatenate(pszLayerDef, strOrderBy);
msFree(strOrderBy);
strOrderBy = NULL;

if( layer->debug )
msDebug("msOGRFileWhichShapes: SQL = %s.\n", pszLayerDef);

/* If nLayerIndex == -1 then the layer is an SQL result ... free it */
if( psInfo->nLayerIndex == -1 )
OGR_DS_ReleaseResultSet( psInfo->hDS, psInfo->hLayer );
psInfo->nLayerIndex = -1;

ACQUIRE_OGR_LOCK;
psInfo->hLayer = OGR_DS_ExecuteSQL( psInfo->hDS, pszLayerDef, NULL, NULL );
msFree(pszLayerDef);
RELEASE_OGR_LOCK;
if( psInfo->hLayer == NULL ) {
msSetError(MS_OGRERR,
"ExecuteSQL(%s) failed.\n%s",
"msOGRFileWhichShapes()",
pszLayerDef, CPLGetLastErrorMsg() );
return MS_FAILURE;
}
}

/* ------------------------------------------------------------------
* Set Spatial filter... this may result in no features being returned
* if layer does not overlap current view.
Expand Down
20 changes: 19 additions & 1 deletion mappostgis.c
Expand Up @@ -1870,11 +1870,13 @@ char *msPostGISBuildSQLWhere(layerObj *layer, rectObj *rect, long *uid)
char *strFilter = 0;
char *strUid = 0;
char *strWhere = 0;
char *strOrderBy = 0;
char *strLimit = 0;
char *strOffset = 0;
size_t strRectLength = 0;
size_t strFilterLength = 0;
size_t strUidLength = 0;
size_t strOrderByLength = 0;
size_t strLimitLength = 0;
size_t strOffsetLength = 0;
size_t bufferSize = 0;
Expand Down Expand Up @@ -1954,8 +1956,17 @@ char *msPostGISBuildSQLWhere(layerObj *layer, rectObj *rect, long *uid)
strUidLength = strlen(strUid);
}

/* Populate strOrderBy, if necessary */
if( layer->sortBy.nProperties > 0 ) {
char* pszTmp = msLayerBuildSQLOrderBy(layer);
strOrderBy = msStringConcatenate(strOrderBy, " ORDER BY ");
strOrderBy = msStringConcatenate(strOrderBy, pszTmp);
msFree(pszTmp);
strOrderByLength = strlen(strOrderBy);
}

bufferSize = strRectLength + 5 + strFilterLength + 5 + strUidLength
+ strLimitLength + strOffsetLength;
+ strLimitLength + strOffsetLength + strOrderByLength;
strWhere = (char*)msSmallMalloc(bufferSize);
*strWhere = '\0';
if ( strRect ) {
Expand All @@ -1979,6 +1990,12 @@ char *msPostGISBuildSQLWhere(layerObj *layer, rectObj *rect, long *uid)
free(strUid);
insert_and++;
}

if ( strOrderBy ) {
strlcat(strWhere, strOrderBy, bufferSize);
free(strOrderBy);
}

if ( strLimit ) {
strlcat(strWhere, strLimit, bufferSize);
free(strLimit);
Expand Down Expand Up @@ -2046,6 +2063,7 @@ char *msPostGISBuildSQL(layerObj *layer, rectObj *rect, long *uid)

strSQL = msSmallMalloc(strlen(strSQLTemplate) + strlen(strFrom) + strlen(strItems) + strlen(strWhere));
sprintf(strSQL, strSQLTemplate, strItems, strFrom, strWhere);

if (strItems) free(strItems);
if (strFrom) free(strFrom);
if (strWhere) free(strWhere);
Expand Down
27 changes: 26 additions & 1 deletion mapserver.h
Expand Up @@ -1487,7 +1487,24 @@ extern "C" {
int n_entries;
scaleTokenEntryObj *tokens;
} scaleTokenObj;


#ifndef SWIG
typedef enum {
SORT_ASC,
SORT_DESC
} sortOrderEnum;

typedef struct {
char* item;
sortOrderEnum sortOrder;
} sortByProperties;

typedef struct {
int nProperties;
sortByProperties* properties;
} sortByClause;
#endif

struct layerObj {

char *classitem; /* .DBF item to be used for symbol lookup */
Expand Down Expand Up @@ -1674,6 +1691,10 @@ extern "C" {
char *utfitem;
int utfitemindex;
expressionObj utfdata;

#ifndef SWIG
sortByClause sortBy;
#endif
};


Expand Down Expand Up @@ -2366,6 +2387,10 @@ void msPopulateTextSymbolForLabelAndString(textSymbolObj *ts, labelObj *l, char
MS_DLL_EXPORT char *msLayerEscapeSQLParam(layerObj *layer, const char* pszString);
MS_DLL_EXPORT char *msLayerEscapePropertyName(layerObj *layer, const char* pszString);

int msLayerSupportsSorting(layerObj *layer);
void msLayerSetSort(layerObj *layer, const sortByClause* sortBy);
char* msLayerBuildSQLOrderBy(layerObj *layer);

/* These are special because SWF is using these */
int msOGRLayerNextShape(layerObj *layer, shapeObj *shape);
int msOGRLayerGetItems(layerObj *layer);
Expand Down

0 comments on commit df08e5b

Please sign in to comment.