static void _mapcache_cache_mbtiles_set(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*)pcache; struct sqlite_conn *conn; mapcache_pooled_connection *pc = mapcache_sqlite_get_conn(ctx,cache,tile,0); if (GC_HAS_ERROR(ctx)) { mapcache_sqlite_release_conn(ctx, pc); return; } conn = SQLITE_CONN(pc); if(!tile->raw_image) { tile->raw_image = mapcache_imageio_decode(ctx, tile->encoded_data); if(GC_HAS_ERROR(ctx)) { mapcache_sqlite_release_conn(ctx, pc); return; } } sqlite3_exec(conn->handle, "BEGIN TRANSACTION", 0, 0, 0); _single_mbtile_set(ctx, cache, tile,conn); if (GC_HAS_ERROR(ctx)) { sqlite3_exec(conn->handle, "ROLLBACK TRANSACTION", 0, 0, 0); } else { sqlite3_exec(conn->handle, "END TRANSACTION", 0, 0, 0); } mapcache_sqlite_release_conn(ctx, pc); }
static void _mapcache_cache_sqlite_delete(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*) pcache; mapcache_pooled_connection *pc; struct sqlite_conn *conn; sqlite3_stmt *stmt; int ret; pc = mapcache_sqlite_get_conn(ctx,cache,tile,0); if (GC_HAS_ERROR(ctx)) { mapcache_sqlite_release_conn(ctx, pc); return; } conn = SQLITE_CONN(pc); stmt = conn->prepared_statements[SQLITE_DEL_TILE_STMT_IDX]; if(!stmt) { sqlite3_prepare(conn->handle, cache->delete_stmt.sql, -1, &conn->prepared_statements[SQLITE_DEL_TILE_STMT_IDX], NULL); stmt = conn->prepared_statements[SQLITE_DEL_TILE_STMT_IDX]; } cache->bind_stmt(ctx, stmt, cache, tile); ret = sqlite3_step(stmt); if (ret != SQLITE_DONE && ret != SQLITE_ROW) { ctx->set_error(ctx, 500, "sqlite backend failed on delete: %s", sqlite3_errmsg(conn->handle)); } sqlite3_reset(stmt); mapcache_sqlite_release_conn(ctx, pc); }
static int _mapcache_cache_sqlite_get(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*) pcache; struct sqlite_conn *conn; sqlite3_stmt *stmt; int ret; mapcache_pooled_connection *pc = mapcache_sqlite_get_conn(ctx,cache,tile,1); if (GC_HAS_ERROR(ctx)) { if(tile->tileset->read_only || !tile->tileset->source) { mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_FAILURE; } else { /* not an error in this case, as the db file may not have been created yet */ ctx->clear_errors(ctx); mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_CACHE_MISS; } } conn = SQLITE_CONN(pc); stmt = conn->prepared_statements[GET_TILE_STMT_IDX]; if(!stmt) { sqlite3_prepare(conn->handle, cache->get_stmt.sql, -1, &conn->prepared_statements[GET_TILE_STMT_IDX], NULL); stmt = conn->prepared_statements[GET_TILE_STMT_IDX]; } cache->bind_stmt(ctx, stmt, cache, tile); do { ret = sqlite3_step(stmt); if (ret != SQLITE_DONE && ret != SQLITE_ROW && ret != SQLITE_BUSY && ret != SQLITE_LOCKED) { ctx->set_error(ctx, 500, "sqlite backend failed on get: %s", sqlite3_errmsg(conn->handle)); sqlite3_reset(stmt); mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_FAILURE; } } while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED); if (ret == SQLITE_DONE) { sqlite3_reset(stmt); mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_CACHE_MISS; } else { const void *blob = sqlite3_column_blob(stmt, 0); int size = sqlite3_column_bytes(stmt, 0); if(size>0 && ((char*)blob)[0] == '#') { tile->encoded_data = mapcache_empty_png_decode(ctx,tile->grid_link->grid->tile_sx, tile->grid_link->grid->tile_sy ,blob,&tile->nodata); } else { tile->encoded_data = mapcache_buffer_create(size, ctx->pool); memcpy(tile->encoded_data->buf, blob, size); tile->encoded_data->size = size; } if (sqlite3_column_count(stmt) > 1) { time_t mtime = sqlite3_column_int64(stmt, 1); apr_time_ansi_put(&(tile->mtime), mtime); } sqlite3_reset(stmt); mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_SUCCESS; } }
static void _mapcache_cache_mbtiles_multi_set(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tiles, int ntiles) { int i; mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*)pcache; mapcache_pooled_connection *pc; struct sqlite_conn *conn; /* decode/encode image data before going into the sqlite write lock */ for (i = 0; i < ntiles; i++) { mapcache_tile *tile = &tiles[i]; if(!tile->raw_image) { tile->raw_image = mapcache_imageio_decode(ctx, tile->encoded_data); GC_CHECK_ERROR(ctx); } /* only encode to image format if tile is not blank */ if (mapcache_image_blank_color(tile->raw_image) != MAPCACHE_TRUE && !tile->encoded_data) { tile->encoded_data = tile->tileset->format->write(ctx, tile->raw_image, tile->tileset->format); GC_CHECK_ERROR(ctx); } } pc = mapcache_sqlite_get_conn(ctx,cache,&tiles[0],0); if (GC_HAS_ERROR(ctx)) { mapcache_sqlite_release_conn(ctx, pc); return; } conn = SQLITE_CONN(pc); sqlite3_exec(conn->handle, "BEGIN TRANSACTION", 0, 0, 0); for (i = 0; i < ntiles; i++) { mapcache_tile *tile = &tiles[i]; _single_mbtile_set(ctx,cache,tile,conn); if(GC_HAS_ERROR(ctx)) break; } if (GC_HAS_ERROR(ctx)) { sqlite3_exec(conn->handle, "ROLLBACK TRANSACTION", 0, 0, 0); } else { sqlite3_exec(conn->handle, "END TRANSACTION", 0, 0, 0); } mapcache_sqlite_release_conn(ctx, pc); }
static void _mapcache_cache_sqlite_multi_set(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tiles, int ntiles) { mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*)pcache; int i; struct sqlite_conn *conn; mapcache_pooled_connection *pc = mapcache_sqlite_get_conn(ctx,cache,&tiles[0],0); if (GC_HAS_ERROR(ctx)) { mapcache_sqlite_release_conn(ctx, pc); return; } conn = SQLITE_CONN(pc); sqlite3_exec(conn->handle, "BEGIN TRANSACTION", 0, 0, 0); for (i = 0; i < ntiles; i++) { mapcache_tile *tile = &tiles[i]; _single_sqlitetile_set(ctx,cache, tile,conn); if(GC_HAS_ERROR(ctx)) break; } if (GC_HAS_ERROR(ctx)) { sqlite3_exec(conn->handle, "ROLLBACK TRANSACTION", 0, 0, 0); } else { sqlite3_exec(conn->handle, "END TRANSACTION", 0, 0, 0); } mapcache_sqlite_release_conn(ctx, pc); }
static int _mapcache_cache_sqlite_has_tile(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*) pcache; mapcache_pooled_connection *pc; struct sqlite_conn *conn; sqlite3_stmt *stmt; int ret; pc = mapcache_sqlite_get_conn(ctx,cache,tile,1); if (GC_HAS_ERROR(ctx)) { if(pc) mapcache_sqlite_release_conn(ctx, pc); if(!tile->tileset->read_only && tile->tileset->source) { /* not an error in this case, as the db file may not have been created yet */ ctx->clear_errors(ctx); } return MAPCACHE_FALSE; } conn = SQLITE_CONN(pc); stmt = conn->prepared_statements[HAS_TILE_STMT_IDX]; if(!stmt) { sqlite3_prepare(conn->handle, cache->exists_stmt.sql, -1, &conn->prepared_statements[HAS_TILE_STMT_IDX], NULL); stmt = conn->prepared_statements[HAS_TILE_STMT_IDX]; } cache->bind_stmt(ctx, stmt, cache, tile); ret = sqlite3_step(stmt); if (ret != SQLITE_DONE && ret != SQLITE_ROW) { ctx->set_error(ctx, 500, "sqlite backend failed on has_tile: %s", sqlite3_errmsg(conn->handle)); } if (ret == SQLITE_DONE) { ret = MAPCACHE_FALSE; } else if (ret == SQLITE_ROW) { ret = MAPCACHE_TRUE; } sqlite3_reset(stmt); mapcache_sqlite_release_conn(ctx, pc); return ret; }
static void _mapcache_cache_mbtiles_delete(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*) pcache; mapcache_pooled_connection *pc; struct sqlite_conn *conn; sqlite3_stmt *stmt1,*stmt2,*stmt3; int ret; const char *tile_id; size_t tile_id_size; pc = mapcache_sqlite_get_conn(ctx,cache,tile,0); if (GC_HAS_ERROR(ctx)) { mapcache_sqlite_release_conn(ctx, pc); return; } conn = SQLITE_CONN(pc); stmt1 = conn->prepared_statements[MBTILES_DEL_TILE_SELECT_STMT_IDX]; stmt2 = conn->prepared_statements[MBTILES_DEL_TILE_STMT1_IDX]; stmt3 = conn->prepared_statements[MBTILES_DEL_TILE_STMT2_IDX]; if(!stmt1) { sqlite3_prepare(conn->handle, "select tile_id from map where tile_col=:x and tile_row=:y and zoom_level=:z",-1,&conn->prepared_statements[MBTILES_DEL_TILE_SELECT_STMT_IDX], NULL); sqlite3_prepare(conn->handle, "delete from map where tile_col=:x and tile_row=:y and zoom_level=:z", -1, &conn->prepared_statements[MBTILES_DEL_TILE_STMT1_IDX], NULL); sqlite3_prepare(conn->handle, "delete from images where tile_id=:foobar", -1, &conn->prepared_statements[MBTILES_DEL_TILE_STMT2_IDX], NULL); stmt1 = conn->prepared_statements[MBTILES_DEL_TILE_SELECT_STMT_IDX]; stmt2 = conn->prepared_statements[MBTILES_DEL_TILE_STMT1_IDX]; stmt3 = conn->prepared_statements[MBTILES_DEL_TILE_STMT2_IDX]; } /* first extract tile_id from the tile we will delete. We need this because we do not know * if the tile is empty or not. * If it is empty, we will not delete the image blob data from the images table */ cache->bind_stmt(ctx, stmt1, cache, tile); do { ret = sqlite3_step(stmt1); if (ret != SQLITE_DONE && ret != SQLITE_ROW && ret != SQLITE_BUSY && ret != SQLITE_LOCKED) { ctx->set_error(ctx, 500, "sqlite backend failed on mbtile del 1: %s", sqlite3_errmsg(conn->handle)); sqlite3_reset(stmt1); mapcache_sqlite_release_conn(ctx, pc); return; } } while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED); if (ret == SQLITE_DONE) { /* tile does not exist, ignore */ sqlite3_reset(stmt1); mapcache_sqlite_release_conn(ctx, pc); return; } else { tile_id = (const char*) sqlite3_column_text(stmt1, 0); tile_id_size = sqlite3_column_bytes(stmt1, 0); } /* delete the tile from the "map" table */ cache->bind_stmt(ctx,stmt2, cache, tile); ret = sqlite3_step(stmt2); if (ret != SQLITE_DONE && ret != SQLITE_ROW) { ctx->set_error(ctx, 500, "sqlite backend failed on mbtile del 2: %s", sqlite3_errmsg(conn->handle)); sqlite3_reset(stmt1); sqlite3_reset(stmt2); mapcache_sqlite_release_conn(ctx, pc); return; } if(tile_id[0] != '#') { /* the tile isn't empty, we must also delete from the images table */ int paramidx = sqlite3_bind_parameter_index(stmt3, ":foobar"); if (paramidx) { sqlite3_bind_text(stmt3, paramidx, tile_id, tile_id_size, SQLITE_STATIC); } ret = sqlite3_step(stmt3); if (ret != SQLITE_DONE && ret != SQLITE_ROW) { ctx->set_error(ctx, 500, "sqlite backend failed on mbtile del 3: %s", sqlite3_errmsg(conn->handle)); sqlite3_reset(stmt1); sqlite3_reset(stmt2); sqlite3_reset(stmt3); mapcache_sqlite_release_conn(ctx, pc); return; } } sqlite3_reset(stmt1); sqlite3_reset(stmt2); sqlite3_reset(stmt3); mapcache_sqlite_release_conn(ctx, pc); }