Skip to content

Commit 806a264

Browse files
committed
Merge branch 'sqlite-dimensions' into branch-1-4
2 parents c7d025b + f9b05a4 commit 806a264

File tree

5 files changed

+232
-35
lines changed

5 files changed

+232
-35
lines changed

include/mapcache.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ typedef struct mapcache_dimension_time mapcache_dimension_time;
156156
typedef struct mapcache_timedimension mapcache_timedimension;
157157
typedef struct mapcache_dimension_intervals mapcache_dimension_intervals;
158158
typedef struct mapcache_dimension_values mapcache_dimension_values;
159+
typedef struct mapcache_dimension_sqlite mapcache_dimension_sqlite;
159160
typedef struct mapcache_dimension_regex mapcache_dimension_regex;
160161
typedef struct mapcache_extent mapcache_extent;
161162
typedef struct mapcache_extent_i mapcache_extent_i;
@@ -1938,7 +1939,8 @@ typedef enum {
19381939
MAPCACHE_DIMENSION_VALUES,
19391940
MAPCACHE_DIMENSION_REGEX,
19401941
MAPCACHE_DIMENSION_INTERVALS,
1941-
MAPCACHE_DIMENSION_TIME
1942+
MAPCACHE_DIMENSION_TIME,
1943+
MAPCACHE_DIMENSION_SQLITE
19421944
} mapcache_dimension_type;
19431945

19441946
struct mapcache_dimension {
@@ -1947,6 +1949,7 @@ struct mapcache_dimension {
19471949
char *unit;
19481950
apr_table_t *metadata;
19491951
char *default_value;
1952+
int skip_validation;
19501953

19511954
/**
19521955
* \brief validate the given value
@@ -1963,7 +1966,7 @@ struct mapcache_dimension {
19631966
*
19641967
* \returns a list of character strings that will be included in the capabilities <dimension> element
19651968
*/
1966-
const char** (*print_ogc_formatted_values)(mapcache_context *context, mapcache_dimension *dimension);
1969+
apr_array_header_t* (*print_ogc_formatted_values)(mapcache_context *context, mapcache_dimension *dimension);
19671970

19681971
/**
19691972
* \brief parse the value given in the configuration
@@ -1978,6 +1981,13 @@ struct mapcache_dimension_values {
19781981
int case_sensitive;
19791982
};
19801983

1984+
struct mapcache_dimension_sqlite {
1985+
mapcache_dimension dimension;
1986+
char *sqlite_db;
1987+
char *validate_query;
1988+
char *list_query;
1989+
};
1990+
19811991
struct mapcache_dimension_regex {
19821992
mapcache_dimension dimension;
19831993
char *regex_string;
@@ -2001,6 +2011,7 @@ struct mapcache_dimension_time {
20012011
};
20022012

20032013
mapcache_dimension* mapcache_dimension_values_create(apr_pool_t *pool);
2014+
mapcache_dimension* mapcache_dimension_sqlite_create(apr_pool_t *pool);
20042015
mapcache_dimension* mapcache_dimension_regex_create(apr_pool_t *pool);
20052016
mapcache_dimension* mapcache_dimension_intervals_create(apr_pool_t *pool);
20062017
mapcache_dimension* mapcache_dimension_time_create(apr_pool_t *pool);

lib/configuration_xml.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ void parseDimensions(mapcache_context *ctx, ezxml_t node, mapcache_tileset *tile
9696
char *name = (char*)ezxml_attr(dimension_node,"name");
9797
char *type = (char*)ezxml_attr(dimension_node,"type");
9898
char *unit = (char*)ezxml_attr(dimension_node,"unit");
99+
char *skip_validation = (char*)ezxml_attr(dimension_node,"skip_validation");
99100
char *default_value = (char*)ezxml_attr(dimension_node,"default");
100101

101102
mapcache_dimension *dimension = NULL;
@@ -112,6 +113,8 @@ void parseDimensions(mapcache_context *ctx, ezxml_t node, mapcache_tileset *tile
112113
dimension = mapcache_dimension_regex_create(ctx->pool);
113114
} else if(!strcmp(type,"intervals")) {
114115
dimension = mapcache_dimension_intervals_create(ctx->pool);
116+
} else if(!strcmp(type,"sqlite")) {
117+
dimension = mapcache_dimension_sqlite_create(ctx->pool);
115118
} else if(!strcmp(type,"time")) {
116119
ctx->set_error(ctx,501,"time dimension type not implemented yet");
117120
return;
@@ -130,6 +133,10 @@ void parseDimensions(mapcache_context *ctx, ezxml_t node, mapcache_tileset *tile
130133
if(unit && *unit) {
131134
dimension->unit = apr_pstrdup(ctx->pool,unit);
132135
}
136+
137+
if(skip_validation && !strcmp(skip_validation,"true")) {
138+
dimension->skip_validation = MAPCACHE_TRUE;
139+
}
133140

134141
if(default_value && *default_value) {
135142
dimension->default_value = apr_pstrdup(ctx->pool,default_value);

lib/dimension.c

Lines changed: 177 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,15 @@ static int _mapcache_dimension_intervals_validate(mapcache_context *ctx, mapcach
6969
return MAPCACHE_FAILURE;
7070
}
7171

72-
static const char** _mapcache_dimension_intervals_print(mapcache_context *ctx, mapcache_dimension *dim)
72+
static apr_array_header_t* _mapcache_dimension_intervals_print(mapcache_context *ctx, mapcache_dimension *dim)
7373
{
7474
mapcache_dimension_intervals *dimension = (mapcache_dimension_intervals*)dim;
75-
const char **ret = (const char**)apr_pcalloc(ctx->pool,(dimension->nintervals+1)*sizeof(const char*));
75+
apr_array_header_t *ret = apr_array_make(ctx->pool,dimension->nintervals,sizeof(char*));
7676
int i;
7777
for(i=0; i<dimension->nintervals; i++) {
7878
mapcache_interval *interval = &dimension->intervals[i];
79-
ret[i] = apr_psprintf(ctx->pool,"%g/%g/%g",interval->start,interval->end,interval->resolution);
79+
APR_ARRAY_PUSH(ret,char*) = apr_psprintf(ctx->pool,"%g/%g/%g",interval->start,interval->end,interval->resolution);
8080
}
81-
ret[i]=NULL;
8281
return ret;
8382
}
8483

@@ -149,12 +148,11 @@ static int _mapcache_dimension_regex_validate(mapcache_context *ctx, mapcache_di
149148
return MAPCACHE_FAILURE;
150149
}
151150

152-
static const char** _mapcache_dimension_regex_print(mapcache_context *ctx, mapcache_dimension *dim)
151+
static apr_array_header_t* _mapcache_dimension_regex_print(mapcache_context *ctx, mapcache_dimension *dim)
153152
{
154153
mapcache_dimension_regex *dimension = (mapcache_dimension_regex*)dim;
155-
const char **ret = (const char**)apr_pcalloc(ctx->pool,2*sizeof(const char*));
156-
ret[0]=dimension->regex_string;
157-
ret[1]=NULL;
154+
apr_array_header_t *ret = apr_array_make(ctx->pool,1,sizeof(char*));
155+
APR_ARRAY_PUSH(ret,char*) = apr_pstrdup(ctx->pool,dimension->regex_string);
158156
return ret;
159157
}
160158

@@ -212,15 +210,14 @@ static int _mapcache_dimension_values_validate(mapcache_context *ctx, mapcache_d
212210
return MAPCACHE_FAILURE;
213211
}
214212

215-
static const char** _mapcache_dimension_values_print(mapcache_context *ctx, mapcache_dimension *dim)
213+
static apr_array_header_t* _mapcache_dimension_values_print(mapcache_context *ctx, mapcache_dimension *dim)
216214
{
217215
mapcache_dimension_values *dimension = (mapcache_dimension_values*)dim;
218-
const char **ret = (const char**)apr_pcalloc(ctx->pool,(dimension->nvalues+1)*sizeof(const char*));
216+
apr_array_header_t *ret = apr_array_make(ctx->pool,dimension->nvalues,sizeof(char*));
219217
int i;
220218
for(i=0; i<dimension->nvalues; i++) {
221-
ret[i] = dimension->values[i];
219+
APR_ARRAY_PUSH(ret,char*) = apr_pstrdup(ctx->pool,dimension->values[i]);
222220
}
223-
ret[i]=NULL;
224221
return ret;
225222
}
226223

@@ -272,6 +269,174 @@ mapcache_dimension* mapcache_dimension_values_create(apr_pool_t *pool)
272269
return (mapcache_dimension*)dimension;
273270
}
274271

272+
#ifdef USE_SQLITE
273+
274+
struct dimension_sqlite_connection {
275+
sqlite3 *handle;
276+
char *errmsg;
277+
};
278+
279+
static struct dimension_sqlite_connection* _mapcache_dimension_sqlite_get_connection(mapcache_context *ctx, mapcache_dimension_sqlite *dim) {
280+
int ret;
281+
int flags;
282+
struct dimension_sqlite_connection *conn = apr_pcalloc(ctx->pool, sizeof (struct dimension_sqlite_connection));
283+
flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_NOMUTEX;
284+
ret = sqlite3_open_v2(dim->sqlite_db, &conn->handle, flags, NULL);
285+
286+
if (ret != SQLITE_OK) {
287+
ctx->set_error(ctx, 500, "failed to open connection to sqlite dimension db file: %s", (conn->handle?sqlite3_errmsg(conn->handle):"unknown error") );
288+
return NULL;
289+
}
290+
sqlite3_busy_timeout(conn->handle, 300000);
291+
return conn;
292+
}
293+
294+
static void _mapcache_dimension_sqlite_release_connection(mapcache_context *ctx, mapcache_dimension_sqlite *dim, struct dimension_sqlite_connection *conn) {
295+
sqlite3_close(conn->handle);
296+
}
297+
298+
static int _mapcache_dimension_sqlite_validate(mapcache_context *ctx, mapcache_dimension *dim, char **value)
299+
{
300+
mapcache_dimension_sqlite *dimension = (mapcache_dimension_sqlite*)dim;
301+
struct dimension_sqlite_connection *conn = NULL;
302+
sqlite3_stmt *stmt = NULL;
303+
int sqliteret,paramidx,ret=MAPCACHE_FAILURE;
304+
305+
conn = _mapcache_dimension_sqlite_get_connection(ctx,dimension);
306+
if(GC_HAS_ERROR(ctx)) {
307+
goto cleanup;
308+
}
309+
310+
sqliteret = sqlite3_prepare_v2(conn->handle, dimension->validate_query, -1, &stmt, NULL);
311+
if(sqliteret != SQLITE_OK) {
312+
ctx->set_error(ctx, 500, "sqlite dimension backend failed on preparing query: %s", sqlite3_errmsg(conn->handle));
313+
goto cleanup;
314+
}
315+
paramidx = sqlite3_bind_parameter_index(stmt, ":dim");
316+
if (paramidx) {
317+
sqliteret = sqlite3_bind_text(stmt, paramidx, *value, -1, SQLITE_STATIC);
318+
if(sqliteret != SQLITE_OK) {
319+
ctx->set_error(ctx,400, "sqlite dimension failed to bind :dim : %s", sqlite3_errmsg(conn->handle));
320+
goto cleanup;
321+
}
322+
}
323+
do {
324+
sqliteret = sqlite3_step(stmt);
325+
if (sqliteret != SQLITE_DONE && sqliteret != SQLITE_ROW && sqliteret != SQLITE_BUSY && sqliteret != SQLITE_LOCKED) {
326+
ctx->set_error(ctx, 500, "sqlite dimension backend failed on query : %s (%d)", sqlite3_errmsg(conn->handle), sqliteret);
327+
goto cleanup;
328+
}
329+
if(sqliteret == SQLITE_ROW) {
330+
const char* dim_modified = (const char*) sqlite3_column_text(stmt, 0);
331+
if(strcmp(dim_modified, *value)) {
332+
*value = apr_pstrdup(ctx->pool, dim_modified);
333+
}
334+
ret = MAPCACHE_SUCCESS;
335+
}
336+
} while (sqliteret == SQLITE_ROW || sqliteret == SQLITE_BUSY || sqliteret == SQLITE_LOCKED);
337+
338+
cleanup:
339+
if(stmt) {
340+
sqlite3_finalize(stmt);
341+
}
342+
if(conn) {
343+
_mapcache_dimension_sqlite_release_connection(ctx,dimension,conn);
344+
}
345+
346+
return ret;
347+
}
348+
349+
static apr_array_header_t* _mapcache_dimension_sqlite_print(mapcache_context *ctx, mapcache_dimension *dim)
350+
{
351+
mapcache_dimension_sqlite *dimension = (mapcache_dimension_sqlite*)dim;
352+
struct dimension_sqlite_connection *conn = NULL;
353+
sqlite3_stmt *stmt = NULL;
354+
int sqliteret;
355+
apr_array_header_t *ret = apr_array_make(ctx->pool,0,sizeof(char*));
356+
357+
conn = _mapcache_dimension_sqlite_get_connection(ctx,dimension);
358+
if(GC_HAS_ERROR(ctx)) {
359+
goto cleanup;
360+
}
361+
362+
sqliteret = sqlite3_prepare_v2(conn->handle, dimension->list_query, -1, &stmt, NULL);
363+
if(sqliteret != SQLITE_OK) {
364+
ctx->set_error(ctx, 500, "sqlite dimension backend failed on preparing query: %s", sqlite3_errmsg(conn->handle));
365+
goto cleanup;
366+
}
367+
do {
368+
sqliteret = sqlite3_step(stmt);
369+
if (sqliteret != SQLITE_DONE && sqliteret != SQLITE_ROW && sqliteret != SQLITE_BUSY && sqliteret != SQLITE_LOCKED) {
370+
ctx->set_error(ctx, 500, "sqlite dimension backend failed on query : %s (%d)", sqlite3_errmsg(conn->handle), sqliteret);
371+
goto cleanup;
372+
}
373+
if(sqliteret == SQLITE_ROW) {
374+
const char* sqdim = (const char*) sqlite3_column_text(stmt, 0);
375+
APR_ARRAY_PUSH(ret,char*) = apr_pstrdup(ctx->pool,sqdim);
376+
}
377+
} while (sqliteret == SQLITE_ROW || sqliteret == SQLITE_BUSY || sqliteret == SQLITE_LOCKED);
378+
379+
cleanup:
380+
if(stmt) {
381+
sqlite3_finalize(stmt);
382+
}
383+
if(conn) {
384+
_mapcache_dimension_sqlite_release_connection(ctx,dimension,conn);
385+
}
386+
387+
return ret;
388+
}
389+
390+
391+
static void _mapcache_dimension_sqlite_parse_xml(mapcache_context *ctx, mapcache_dimension *dim,
392+
ezxml_t node)
393+
{
394+
mapcache_dimension_sqlite *dimension;
395+
ezxml_t child;
396+
397+
dimension = (mapcache_dimension_sqlite*)dim;
398+
399+
child = ezxml_child(node,"dbfile");
400+
if(child) {
401+
dimension->sqlite_db = apr_pstrdup(ctx->pool, child->txt);
402+
} else {
403+
ctx->set_error(ctx,400,"sqlite dimension \"%s\" has no <dbfile> node", dim->name);
404+
return;
405+
}
406+
child = ezxml_child(node,"validate_query");
407+
if(child) {
408+
dimension->validate_query = apr_pstrdup(ctx->pool, child->txt);
409+
} else {
410+
ctx->set_error(ctx,400,"sqlite dimension \"%s\" has no <validate_query> node", dim->name);
411+
return;
412+
}
413+
child = ezxml_child(node,"list_query");
414+
if(child) {
415+
dimension->list_query = apr_pstrdup(ctx->pool, child->txt);
416+
} else {
417+
ctx->set_error(ctx,400,"sqlite dimension \"%s\" has no <list_query> node", dim->name);
418+
return;
419+
}
420+
421+
}
422+
423+
#endif
424+
425+
mapcache_dimension* mapcache_dimension_sqlite_create(apr_pool_t *pool)
426+
{
427+
#ifdef USE_SQLITE
428+
mapcache_dimension_sqlite *dimension = apr_pcalloc(pool, sizeof(mapcache_dimension_sqlite));
429+
dimension->dimension.type = MAPCACHE_DIMENSION_SQLITE;
430+
dimension->sqlite_db = NULL;
431+
dimension->dimension.validate = _mapcache_dimension_sqlite_validate;
432+
dimension->dimension.configuration_parse_xml = _mapcache_dimension_sqlite_parse_xml;
433+
dimension->dimension.print_ogc_formatted_values = _mapcache_dimension_sqlite_print;
434+
return (mapcache_dimension*)dimension;
435+
#else
436+
return NULL;
437+
#endif
438+
}
439+
275440
mapcache_dimension* mapcache_dimension_time_create(apr_pool_t *pool)
276441
{
277442
mapcache_dimension_time *dimension = apr_pcalloc(pool, sizeof(mapcache_dimension_time));

lib/service_wms.c

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,9 @@ void _create_capabilities_wms(mapcache_context *ctx, mapcache_request_get_capabi
228228

229229
if(tileset->dimensions) {
230230
for(i=0; i<tileset->dimensions->nelts; i++) {
231-
const char **value;
232-
char *dimval;
231+
apr_array_header_t *values;
232+
int value_idx;
233+
char *dimval = NULL;
233234
mapcache_dimension *dimension = APR_ARRAY_IDX(tileset->dimensions,i,mapcache_dimension*);
234235
ezxml_t dimxml = ezxml_add_child(layerxml,"Dimension",0);
235236
ezxml_set_attr(dimxml,"name",dimension->name);
@@ -238,12 +239,14 @@ void _create_capabilities_wms(mapcache_context *ctx, mapcache_request_get_capabi
238239
if(dimension->unit) {
239240
ezxml_set_attr(dimxml,"units",dimension->unit);
240241
}
241-
value = dimension->print_ogc_formatted_values(ctx,dimension);
242-
dimval = apr_pstrdup(ctx->pool,*value);
243-
value++;
244-
while(*value) {
245-
dimval = apr_pstrcat(ctx->pool,dimval,",",*value,NULL);
246-
value++;
242+
values = dimension->print_ogc_formatted_values(ctx,dimension);
243+
for(value_idx=0;value_idx<values->nelts;value_idx++) {
244+
char *idval = APR_ARRAY_IDX(values,value_idx,char*);
245+
if(dimval) {
246+
dimval = apr_pstrcat(ctx->pool,dimval,",",idval,NULL);
247+
} else {
248+
dimval = apr_pstrdup(ctx->pool,idval);
249+
}
247250
}
248251
ezxml_set_txt(dimxml,dimval);
249252
}
@@ -657,17 +660,28 @@ void _mapcache_service_wms_parse_request(mapcache_context *ctx, mapcache_service
657660
const char *value;
658661
if(tileset->dimensions) {
659662
for(i=0; i<tileset->dimensions->nelts; i++) {
663+
char *dim_name;
660664
mapcache_dimension *dimension = APR_ARRAY_IDX(tileset->dimensions,i,mapcache_dimension*);
661-
if((value = (char*)apr_table_get(params,dimension->name)) != NULL) {
665+
if(!strcasecmp(dimension->name,"TIME") || !strcasecmp(dimension->name,"ELEVATION")) {
666+
dim_name = dimension->name;
667+
} else {
668+
dim_name = apr_pstrcat(ctx->pool, "dim_", dimension->name, NULL);
669+
}
670+
if((value = (char*)apr_table_get(params,dim_name)) != NULL) {
662671
char *tmpval = apr_pstrdup(ctx->pool,value);
663-
int ok = dimension->validate(ctx,dimension,&tmpval);
664-
GC_CHECK_ERROR(ctx);
672+
int ok;
673+
if(dimension->skip_validation) {
674+
ok = MAPCACHE_SUCCESS;
675+
} else {
676+
ok = dimension->validate(ctx,dimension,&tmpval);
677+
GC_CHECK_ERROR(ctx);
678+
}
665679
if(ok == MAPCACHE_SUCCESS)
666680
apr_table_setn(dimtable,dimension->name,tmpval);
667681
else {
668682
errcode = 400;
669683
errmsg = apr_psprintf(ctx->pool, "dimension \"%s\" value \"%s\" fails to validate",
670-
dimension->name, value);
684+
dim_name, value);
671685
goto proxies;
672686
}
673687
}

0 commit comments

Comments
 (0)