@@ -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+
275440mapcache_dimension * mapcache_dimension_time_create (apr_pool_t * pool )
276441{
277442 mapcache_dimension_time * dimension = apr_pcalloc (pool , sizeof (mapcache_dimension_time ));
0 commit comments