Permalink
Browse files

Follow simple equality and range work done pre-7.0/RFC 91.

  • Loading branch information...
sdlime committed Sep 18, 2014
1 parent 2e99414 commit edbbf0ffbb922b61523c4016da77c38177d9e8d1
Showing with 90 additions and 214 deletions.
  1. +90 −214 mappostgis.c
View
@@ -2677,6 +2677,8 @@ int msPostGISLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery)
msDebug("msPostGISLayerWhichShapes query: %s\n", strSQL);
}
// fprintf(stderr, "SQL: %s\n", strSQL);
if(num_bind_values > 0) {
pgresult = PQexecParams(layerinfo->pgconn, strSQL, num_bind_values, NULL, (const char**)layer_bind_values, NULL, NULL, 1);
} else {
@@ -3337,13 +3339,13 @@ int postgresTimeStampForTimeString(const char *timestring, char *dest, size_t de
* timecol < date_trunc(timestring,resolution) + interval '1 resolution'
* )
*/
int createPostgresTimeCompareSimple(const char *timecol, const char *timestring, char *dest, size_t destsize)
int createPostgresTimeCompareEquals(const char *timestring, char *dest, size_t destsize)
{
int timeresolution = msTimeGetResolution(timestring);
char timeStamp[100];
char *interval;
if (timeresolution < 0)
return MS_FALSE;
if (timeresolution < 0) return MS_FALSE;
postgresTimeStampForTimeString(timestring,timeStamp,100);
switch(timeresolution) {
@@ -3368,8 +3370,43 @@ int createPostgresTimeCompareSimple(const char *timecol, const char *timestring,
default:
return MS_FAILURE;
}
snprintf(dest, destsize,"(%s >= date_trunc('%s',%s) and %s < date_trunc('%s',%s) + interval '1 %s')",
timecol, interval, timeStamp, timecol, interval, timeStamp, interval);
snprintf(dest, destsize, " between date_trunc('%s',%s) and date_trunc('%s',%s) + interval '1 %s' - interval '1 second'", interval, timeStamp, interval, timeStamp, interval);
return MS_SUCCESS;
}
int createPostgresTimeCompareGreaterThan(const char *timestring, char *dest, size_t destsize)
{
int timeresolution = msTimeGetResolution(timestring);
char timestamp[100];
char *interval;
if (timeresolution < 0) return MS_FALSE;
postgresTimeStampForTimeString(timestring,timestamp,100);
switch(timeresolution) {
case TIME_RESOLUTION_YEAR:
interval = "year";
break;
case TIME_RESOLUTION_MONTH:
interval = "month";
break;
case TIME_RESOLUTION_DAY:
interval = "day";
break;
case TIME_RESOLUTION_HOUR:
interval = "hour";
break;
case TIME_RESOLUTION_MINUTE:
interval = "minute";
break;
case TIME_RESOLUTION_SECOND:
interval = "second";
break;
default:
return MS_FAILURE;
}
snprintf(dest, destsize,"date_trunc('%s',%s)", interval, timestamp);
return MS_SUCCESS;
}
@@ -3390,160 +3427,41 @@ int createPostgresTimeCompareSimple(const char *timecol, const char *timestring,
* timecol < date_trunc(maxtimestring,maxresolution) + interval '1 maxresolution'
* )
*/
int createPostgresTimeCompareRange(const char *timecol, const char *mintime, const char *maxtime,
char *dest, size_t destsize)
{
int mintimeresolution = msTimeGetResolution(mintime);
int maxtimeresolution = msTimeGetResolution(maxtime);
char minTimeStamp[100];
char maxTimeStamp[100];
char *minTimeInterval,*maxTimeInterval;
if (mintimeresolution < 0 || maxtimeresolution < 0)
return MS_FALSE;
postgresTimeStampForTimeString(mintime,minTimeStamp,100);
postgresTimeStampForTimeString(maxtime,maxTimeStamp,100);
int createPostgresTimeCompareLessThan(const char *timestring, char *dest, size_t destsize)
{
int timeresolution = msTimeGetResolution(timestring);
char timestamp[100];
char *interval;
if (timeresolution < 0)return MS_FALSE;
switch(maxtimeresolution) {
case TIME_RESOLUTION_YEAR:
maxTimeInterval = "year";
break;
case TIME_RESOLUTION_MONTH:
maxTimeInterval = "month";
break;
case TIME_RESOLUTION_DAY:
maxTimeInterval = "day";
break;
case TIME_RESOLUTION_HOUR:
maxTimeInterval = "hour";
break;
case TIME_RESOLUTION_MINUTE:
maxTimeInterval = "minute";
break;
case TIME_RESOLUTION_SECOND:
maxTimeInterval = "second";
break;
default:
return MS_FAILURE;
}
switch(mintimeresolution) {
postgresTimeStampForTimeString(timestring,timestamp,100);
switch(timeresolution) {
case TIME_RESOLUTION_YEAR:
minTimeInterval = "year";
interval = "year";
break;
case TIME_RESOLUTION_MONTH:
minTimeInterval = "month";
interval = "month";
break;
case TIME_RESOLUTION_DAY:
minTimeInterval = "day";
interval = "day";
break;
case TIME_RESOLUTION_HOUR:
minTimeInterval = "hour";
interval = "hour";
break;
case TIME_RESOLUTION_MINUTE:
minTimeInterval = "minute";
interval = "minute";
break;
case TIME_RESOLUTION_SECOND:
minTimeInterval = "second";
interval = "second";
break;
default:
return MS_FAILURE;
}
snprintf(dest, destsize,"(%s >= date_trunc('%s',%s) and %s < date_trunc('%s',%s) + interval '1 %s')",
timecol, minTimeInterval, minTimeStamp,
timecol, maxTimeInterval, maxTimeStamp, maxTimeInterval);
snprintf(dest, destsize,"(date_trunc('%s',%s) + interval '1 %s' - interval '1 second')", interval, timestamp, interval);
return MS_SUCCESS;
}
int msPostGISLayerSetTimeFilter(layerObj *lp, const char *timestring, const char *timefield)
{
char **atimes, **aranges = NULL;
int numtimes=0,i=0,numranges=0;
size_t buffer_size = 512;
char buffer[512], bufferTmp[512];
char* escapedTimeField;
buffer[0] = '\0';
bufferTmp[0] = '\0';
if (!lp || !timestring || !timefield)
return MS_FALSE;
/* Avoid the risk of SQL injection from the timestring */
if( strchr(timestring,'\'') || strchr(timestring, '\\') ) {
msSetError(MS_MISCERR, "Invalid time filter.", "msPostGISLayerSetTimeFilter()");
return MS_FALSE;
}
escapedTimeField = msLayerEscapePropertyName(lp, timefield);
/* discrete time */
if (strstr(timestring, ",") == NULL &&
strstr(timestring, "/") == NULL) { /* discrete time */
createPostgresTimeCompareSimple(escapedTimeField, timestring, buffer, buffer_size);
} else {
/* multiple times, or ranges */
atimes = msStringSplit (timestring, ',', &numtimes);
if (atimes == NULL || numtimes < 1) {
msFree(escapedTimeField);
msFreeCharArray(atimes, numtimes);
return MS_FALSE;
}
strlcat(buffer, "(", buffer_size);
for(i=0; i<numtimes; i++) {
if(i!=0) {
strlcat(buffer, " OR ", buffer_size);
}
strlcat(buffer, "(", buffer_size);
aranges = msStringSplit(atimes[i], '/', &numranges);
if(!aranges) {
msFree(escapedTimeField);
msFreeCharArray(atimes, numtimes);
return MS_FALSE;
}
if(numranges == 1) {
/* we don't have range, just a simple time */
createPostgresTimeCompareSimple(escapedTimeField, atimes[i], bufferTmp, buffer_size);
strlcat(buffer, bufferTmp, buffer_size);
} else if(numranges == 2) {
/* we have a range */
createPostgresTimeCompareRange(escapedTimeField, aranges[0], aranges[1], bufferTmp, buffer_size);
strlcat(buffer, bufferTmp, buffer_size);
} else {
msFree(escapedTimeField);
msFreeCharArray(aranges, numranges);
msFreeCharArray(atimes, numtimes);
return MS_FALSE;
}
msFreeCharArray(aranges, numranges);
strlcat(buffer, ")", buffer_size);
}
strlcat(buffer, ")", buffer_size);
msFreeCharArray(atimes, numtimes);
}
msFree(escapedTimeField);
if(!*buffer) {
return MS_FALSE;
}
/* if the filter is set and it's a string type, concatenate it with the time. If not just free it */
if (lp->filter.type == MS_STRING && !lp->filteritem && lp->filter.string) {
snprintf(bufferTmp, buffer_size, "(%s) and %s", lp->filter.string, buffer);
msLoadExpressionString(&lp->filter, bufferTmp);
} else {
msFreeExpression(&lp->filter);
msLoadExpressionString(&lp->filter, buffer);
}
if(lp->filteritem) free(lp->filteritem);
/* lp->filteritem = msStrdup(timefield); - we're building SQL, filteritem should not be set */
lp->filter.type = MS_STRING; /* force expression to string type so it's interpreted as native SQL */
return MS_TRUE;
}
char *msPostGISEscapeSQLParam(layerObj *layer, const char *pszString)
{
#ifdef USE_POSTGIS
@@ -3655,6 +3573,9 @@ int msPostGISLayerTranslateFilter(layerObj *layer, expressionObj *filter, char *
char *strtmpl = NULL;
char *stresc = NULL;
int comparisonToken = -1;
int bindingToken = -1;
msPostGISLayerInfo *layerinfo = layer->layerinfo;
if(!filter->string) return MS_SUCCESS; /* not an error, just nothing to do */
@@ -3713,6 +3634,18 @@ int msPostGISLayerTranslateFilter(layerObj *layer, expressionObj *filter, char *
node = filter->tokens;
while (node != NULL) {
/*
** Do any token caching/tracking here, easier to have it in one place.
*/
if(node->token == MS_TOKEN_BINDING_TIME) {
bindingToken = node->token;
} else if(node->token == MS_TOKEN_COMPARISON_EQ || node->token == MS_TOKEN_COMPARISON_NE ||
node->token == MS_TOKEN_COMPARISON_GT || node->token == MS_TOKEN_COMPARISON_GE ||
node->token == MS_TOKEN_COMPARISON_LT || node->token == MS_TOKEN_COMPARISON_LE) {
comparisonToken = node->token;
}
switch(node->token) {
/* literal tokens */
@@ -3739,54 +3672,19 @@ int msPostGISLayerTranslateFilter(layerObj *layer, expressionObj *filter, char *
msFree(stresc);
break;
case MS_TOKEN_LITERAL_TIME: {
resolution = msTimeGetResolution(node->tokensrc);
noDate = MS_FALSE;
if(node->tokensrc[0] == 'T') noDate = MS_TRUE;
snippet = (char *) msSmallMalloc(128);
switch(resolution) {
case TIME_RESOLUTION_YEAR:
strtmpl = "to_date('%d','YYYY')";
sprintf(snippet, strtmpl, (node->tokenval.tmval.tm_year+1900));
break;
case TIME_RESOLUTION_MONTH:
strtmpl = "to_date('%d-%02d','YYYY-MM')";
sprintf(snippet, strtmpl, (node->tokenval.tmval.tm_year+1900), (node->tokenval.tmval.tm_mon+1));
break;
case TIME_RESOLUTION_DAY:
strtmpl = "to_date('%d-%02d-%02d','YYYY-MM-DD')";
sprintf(snippet, strtmpl, (node->tokenval.tmval.tm_year+1900), (node->tokenval.tmval.tm_mon+1), node->tokenval.tmval.tm_mday);
break;
case TIME_RESOLUTION_HOUR:
if(noDate) {
strtmpl = "to_timestamp('%02d','hh24')::time";
sprintf(snippet, strtmpl, node->tokenval.tmval.tm_hour);
} else {
strtmpl = "to_timestamp('%d-%02d-%02d %02d','YYYY-MM-DD hh24')";
sprintf(snippet, strtmpl, (node->tokenval.tmval.tm_year+1900), (node->tokenval.tmval.tm_mon+1), node->tokenval.tmval.tm_mday, node->tokenval.tmval.tm_hour);
}
break;
case TIME_RESOLUTION_MINUTE:
if(noDate) {
strtmpl = "to_timestamp('%02d:%02d','hh24:mi')::time";
sprintf(snippet, strtmpl, node->tokenval.tmval.tm_hour, node->tokenval.tmval.tm_min);
} else {
strtmpl = "to_timestamp('%d-%02d-%02d %02d:%02d','YYYY-MM-DD hh24:mi')";
sprintf(snippet, strtmpl, (node->tokenval.tmval.tm_year+1900), (node->tokenval.tmval.tm_mon+1), node->tokenval.tmval.tm_mday, node->tokenval.tmval.tm_hour, node->tokenval.tmval.tm_min);
}
break;
case TIME_RESOLUTION_SECOND:
if(noDate) {
strtmpl = "to_timestamp('%02d:%02d:%02d','hh24:mi:ss')::time";
sprintf(snippet, strtmpl, node->tokenval.tmval.tm_hour, node->tokenval.tmval.tm_min, node->tokenval.tmval.tm_sec);
} else {
strtmpl = "to_timestamp('%d-%02d-%02d %02d:%02d:%02d','YYYY-MM-DD hh24:mi:ss')";
sprintf(snippet, strtmpl, (node->tokenval.tmval.tm_year+1900), (node->tokenval.tmval.tm_mon+1), node->tokenval.tmval.tm_mday, node->tokenval.tmval.tm_hour, node->tokenval.tmval.tm_min, node->tokenval.tmval.tm_sec);
}
break;
snippet = (char *) msSmallMalloc(512);
if(comparisonToken == MS_TOKEN_COMPARISON_EQ) { // TODO: support !=
createPostgresTimeCompareEquals(node->tokensrc, snippet, 512);
} else if(comparisonToken == MS_TOKEN_COMPARISON_GT || comparisonToken == MS_TOKEN_COMPARISON_GE) {
createPostgresTimeCompareGreaterThan(node->tokensrc, snippet, 512);
} else if(comparisonToken == MS_TOKEN_COMPARISON_LT || comparisonToken == MS_TOKEN_COMPARISON_LE) {
createPostgresTimeCompareLessThan(node->tokensrc, snippet, 512);
} else {
goto cleanup;
}
comparisonToken = -1; bindingToken = -1; /* reset */
native_string = msStringConcatenate(native_string, snippet);
msFree(snippet);
break;
@@ -3816,35 +3714,8 @@ int msPostGISLayerTranslateFilter(layerObj *layer, expressionObj *filter, char *
sprintf(snippet, strtmpl, stresc);
native_string = msStringConcatenate(native_string, snippet);
msFree(snippet);
msFree(stresc);
break;
/*case MS_TOKEN_BINDING_TIME: {
tokenListNodeObjPtr literalTimeNode = findNextTokenByType(node->next, MS_TOKEN_LITERAL_TIME);
if(literalTimeNode != NULL) {
resolution = msTimeGetResolution(literalTimeNode->tokensrc);
noDate = MS_FALSE;
if(literalTimeNode->tokensrc[0] == 'T') noDate = MS_TRUE;
if(resolution == TIME_RESOLUTION_HOUR || resolution == TIME_RESOLUTION_MINUTE || resolution == TIME_RESOLUTION_SECOND) {
if(noDate)
strtmpl = "%s::time";
else
strtmpl = "%s::timestamp";
} else
strtmpl = "%s::date";
strtmpl = "%s";
stresc = msLayerEscapePropertyName(layer, node->tokenval.bindval.item);
snippet = (char *) msSmallMalloc(strlen(strtmpl) + strlen(stresc));
sprintf(snippet, strtmpl, stresc);
native_string = msStringConcatenate(native_string, snippet);
msFree(snippet);
msFree(stresc);
} // else handle as above
msFree(stresc);
break;
}*/
case MS_TOKEN_BINDING_SHAPE:
native_string = msStringConcatenate(native_string, layerinfo->geomcolumn);
break;
@@ -3893,8 +3764,13 @@ int msPostGISLayerTranslateFilter(layerObj *layer, expressionObj *filter, char *
default:
/* by default accept the general token to string conversion */
if(bindingToken == MS_TOKEN_BINDING_TIME && (node->token == MS_TOKEN_COMPARISON_EQ || node->token == MS_TOKEN_COMPARISON_NE)) break; /* skip, handled elsewhere */
native_string = msStringConcatenate(native_string, msExpressionTokenToString(node->token));
break;
}
node = node->next;
}
}

0 comments on commit edbbf0f

Please sign in to comment.