]> err.no Git - mapper/blobdiff - src/osm-db-import.c
Remove old map sources
[mapper] / src / osm-db-import.c
index 1bb3bf0a489a78dc6aad54a1dddf2aff6ad4d801..45aa325839d31ec15dd90e0ce2fc6ac6526643aa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of mapper
  *
- * Copyright (C) 2007 Kaj-Michael Lang
+ * Copyright (C) 2008 Kaj-Michael Lang
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 /* Use g_convert to transliterate names.. my iconv seems to be fucked so this didn't work... */
 /* #define TRANSLIT_NAMES */
 
-#define FILE_BUFFER 65535
+#define FILE_BUFFER (128*1024)
 
-static guint node_cnt=0;
-static guint node_skip_cnt=0;
-static guint noded_cnt=0;
-static guint way_cnt=0;
-static guint way_names=0;
-static guint way_refs=0;
+static guint node_cnt=0;               /* Nodes */
+static guint node_skip_cnt=0;  /* Skipped nodes */
+static guint noded_cnt=0;              /* Nodes with (usable) data */
+static guint way_cnt=0;                        /* Ways */
+static guint way_names=0;              /* Ways with name */
+static guint way_refs=0;               /* Ways with ref or int_ref */
 
 static guint dbnode_cnt=0;
 static guint dbnoded_cnt=0;
 static guint dbway_cnt=0;
 
+/* For threaded importing */
+static GThread* import_thread=NULL;
+static GSourceFunc osm_import_progress_cb=NULL;
+static osm_import_data_req osm_import_req;
+static guint import_sid=0;
+
 static gboolean is_update=FALSE;
 static XML_Parser xp;
 
-
 /* XML tag IDs */
 typedef enum {
        START,
@@ -113,7 +118,7 @@ struct _nodeinfo {
        { "amenity", "biergarten",      NODE_AMENITY_PUB },
        { "amenity", "cafe",            NODE_AMENITY_CAFE },
        { "amenity", "fast_food",       NODE_AMENITY_FOOD },
-       { "amenity", "restaurant",      NODE_AMENITY_FOOD },
+       { "amenity", "restaurant",      NODE_AMENITY_RESTAURANT },
 
        { "amenity", "telephone",       NODE_AMENITY_TELEPHONE },
        { "amenity", "toilets",         NODE_AMENITY_WC },
@@ -132,6 +137,7 @@ struct _nodeinfo {
        { "amenity", "bank",            NODE_AMENITY_BANK },
 
        { "amenity", "police",          NODE_AMENITY_POLICE },
+
        { "amenity", "speed_trap",      NODE_AMENITY_SPEEDCAM },
        { "amenity", "speed_camera",    NODE_AMENITY_SPEEDCAM },
        { "amenity", "speed camera",    NODE_AMENITY_SPEEDCAM },
@@ -142,15 +148,15 @@ struct _nodeinfo {
        { "amenity", "college",         NODE_AMENITY_COLLEGE },
        { "amenity", "university",      NODE_AMENITY_COLLEGE },
 
-       { "amenity", "library", NODE_AMENITY_LIBRARY },
+       { "amenity", "library",         NODE_AMENITY_LIBRARY },
        { "amenity", "townhall",        NODE_AMENITY_TOWNHALL },
 
-       { "amenity", "supermarket",     NODE_AMENITY_SHOP },
-       { "amenity", "shopping_centre", NODE_AMENITY_SHOP },
+       { "amenity", "supermarket",     NODE_AMENITY_SHOP_SUPERMARKET },
+       { "amenity", "shopping_centre", NODE_AMENITY_SHOPPING_CENTER },
        { "amenity", "shop",            NODE_AMENITY_SHOP },
        { "amenity", "shops",           NODE_AMENITY_SHOP },
-       { "amenity", "shopping",        NODE_AMENITY_SHOP },
-       { "amenity", "shopping_mall",NODE_AMENITY_SHOP },
+       { "amenity", "shopping",        NODE_AMENITY_SHOPPING_CENTER },
+       { "amenity", "shopping_mall",NODE_AMENITY_SHOPPING_CENTER },
        { "amenity", "cycle_shop",      NODE_AMENITY_SHOP },
        { "amenity", "bike_shop",       NODE_AMENITY_SHOP },
        { "amenity", "coffee_shop",     NODE_AMENITY_SHOP },
@@ -159,11 +165,11 @@ struct _nodeinfo {
        { "amenity", "tea_shop",        NODE_AMENITY_SHOP },
 
        /* Shops */
-       { "shop",        "supermarket", NODE_AMENITY_SHOP },
+       { "shop",        "supermarket", NODE_AMENITY_SHOP_SUPERMARKET },
+       { "shop",        "alcohol",             NODE_AMENITY_SHOP_ALCOHOL },
+       { "shop",        "flowers",             NODE_AMENITY_SHOP_FLOWERS },
        { "shop",        "bakery",              NODE_AMENITY_SHOP },
-       { "shop",        "alcohol",             NODE_AMENITY_SHOP }, 
        { "shop",        "butcher",             NODE_AMENITY_SHOP },
-       { "shop",        "flowers",             NODE_AMENITY_SHOP },
        { "shop",        "clothing",    NODE_AMENITY_SHOP },
        { "shop",        "souvenir",    NODE_AMENITY_SHOP },
        { "shop",        "bicycles",    NODE_AMENITY_SHOP },
@@ -176,6 +182,8 @@ struct _nodeinfo {
        { "shop",        "general_store",NODE_AMENITY_SHOP },
        { "shop",        "food",                NODE_AMENITY_SHOP },
        { "shop",        "drinks",              NODE_AMENITY_SHOP },
+       { "shop",        "sex",                 NODE_AMENITY_SHOP_ADULT },
+
        { "shop",        "pharmacy",    NODE_AMENITY_PHARMACY },
 
        /* Sport */
@@ -233,6 +241,7 @@ struct _nodeinfo {
        { "railway", "halt",            NODE_RAILWAY_HALT },
 
        { "aeroway", "terminal",        NODE_AIRPORT_TERMINAL },
+       { "aeroway", "aerodrome",       NODE_AIRPORT_TERMINAL },
 
        /* Places */    
        { "place", "city",                      NODE_PLACE_CITY },
@@ -312,14 +321,21 @@ static node *cnode=NULL;
 static way *cway=NULL;
 
 struct sql_stmt {
+       /* POIs */
        sqlite3_stmt *insert_poi;
        sqlite3_stmt *delete_osm_poi;
 
+       /* Places */
+       sqlite3_stmt *insert_place;
+       sqlite3_stmt *delete_places;
+
+       /* Nodes */
        sqlite3_stmt *insert_node;
        sqlite3_stmt *delete_nodes;
        sqlite3_stmt *select_node;
        sqlite3_stmt *update_node;
 
+       /* Ways */
        sqlite3_stmt *insert_way_data;
        sqlite3_stmt *insert_way_ref;
        sqlite3_stmt *insert_way_pc;
@@ -332,22 +348,18 @@ struct sql_stmt {
        sqlite3_stmt *delete_way_names_nls;
        sqlite3_stmt *delete_way_ref;
        sqlite3_stmt *delete_way_pc;
-
-       sqlite3_stmt *insert_place;
-       sqlite3_stmt *delete_place;
 };
 static struct sql_stmt sql;
 
-
 static struct map_bbox bbox;
 static gboolean use_bbox;
 
-void osm_free_way_data(way *w);
-void print_way(way *w);
+static void osm_free_way_data(way *w);
+static void print_way(way *w);
 
-void db_prepare(sqlite3 *db);
-gboolean db_insert_node(node *n);
-guint32 osm_find_way_place(way *w, node_type_t nt);
+static gboolean osm_db_prepare(sqlite3 *db);
+static gboolean db_insert_node(node *n);
+static guint32 osm_find_way_place(way *w, node_type_t nt);
 
 /****************************************************/
 /* Functions */
@@ -365,7 +377,7 @@ sqlite3_finalize(sql.delete_nodes);
 sqlite3_finalize(sql.update_node);
 
 sqlite3_finalize(sql.insert_place);
-sqlite3_finalize(sql.delete_place);
+sqlite3_finalize(sql.delete_places);
 
 sqlite3_finalize(sql.delete_way);
 sqlite3_finalize(sql.insert_way_data);
@@ -383,8 +395,8 @@ sqlite3_finalize(sql.delete_way_names_nls);
 sqlite3_finalize(sql.insert_way_names_nls);
 }
 
-void
-db_prepare(sqlite3 *db)
+static gboolean
+osm_db_prepare(sqlite3 *db)
 {
 /* Way nodes */
 sqlite3_prepare_v2(db, "insert or replace into nodes (nid,ilat,ilon,rlat,rlon,l,f) values (?,?,?,?,?,0,?)", -1, &sql.insert_node, NULL);
@@ -394,7 +406,7 @@ sqlite3_prepare_v2(db, "update nodes set l=l+1 where nid=?", -1, &sql.update_nod
 
 /* Places */
 sqlite3_prepare_v2(db, "insert or replace into places (nid,type,name,isin_c,isin_p) values (?, ?, ?, ?, ?)", -1, &sql.insert_place, NULL);
-sqlite3_prepare_v2(db, "delete from places", -1, &sql.delete_place, NULL);
+sqlite3_prepare_v2(db, "delete from places", -1, &sql.delete_places, NULL);
 
 /* POI nodes */
 if (sqlite3_prepare_v2(db, "insert or replace into poi (osm_id, lat, lon, label, cat_id, public, source, priority, isin_c, isin_p, desc, url, postal_code) "
@@ -426,11 +438,13 @@ sqlite3_prepare_v2(db, "delete from way_names_nls where wid=?", -1, &sql.delete_
 /* Way ref and int_ref */
 sqlite3_prepare_v2(db, "insert or replace into way_ref (rid,ref,int_ref) values (?, ?, ?)", -1, &sql.insert_way_ref, NULL);
 sqlite3_prepare_v2(db, "delete from way_ref", -1, &sql.delete_way_ref, NULL);
+
+return TRUE;
 }
 
 /********************************************************************/
 
-void
+static void
 print_way(way *w)
 {
 #ifdef VERBOSE
@@ -449,7 +463,7 @@ g_printf("Way #%d(N:%d T:%d S:%d IS: %d/%d): %s [%s:%s:%s]\n",
 #endif
 }
 
-void
+static void
 print_node(node *n)
 {
 #ifdef VERBOSE
@@ -465,7 +479,7 @@ g_printf("Node #%d: T:%d IS: %d/%d [%s]\n",
 
 /********************************************************************/
 
-gboolean
+static gboolean
 db_insert_node(node *n)
 {
 gint32 lat, lon;
@@ -551,20 +565,9 @@ return db_exec(db,sql.update_node);
 static gboolean
 db_insert_way_n2n(way *w, node *nf, node *nt)
 {
-if (!w) {
-       g_printf("NULL WAY\n");
-       return FALSE;
-}
-
-if (!nf) {
-       g_printf("NULL NODE 1\n");
-       return FALSE;
-}
-
-if (!nt) {
-       g_printf("NULL NODE 2\n");
-       return FALSE;
-}
+g_return_val_if_fail(w, FALSE);
+g_return_val_if_fail(nf, FALSE);
+g_return_val_if_fail(nt, FALSE);
 
 sqlite3_bind_int(sql.insert_way_n2n, 1, w->id);
 sqlite3_bind_int(sql.insert_way_n2n, 2, nf->id);
@@ -583,14 +586,14 @@ return TRUE;
 /**
  * Insert way ref and int_ref
  */
-static void 
+static gboolean 
 db_insert_way_ref(way *w)
 {
 if (!w->data)
-       return;
+       return TRUE;
 
 if (!w->data->ref && !w->data->int_ref)
-       return;
+       return TRUE;
 
 way_refs++;
 
@@ -600,21 +603,19 @@ if (w->data->ref)
 if (w->data->int_ref)
        sqlite3_bind_text(sql.insert_way_ref, 3, w->data->int_ref, -1, SQLITE_TRANSIENT);
 
-db_exec(db,sql.insert_way_ref);
+return db_exec(db,sql.insert_way_ref);
 }
 
 /**
  * Insert way name
  */
-static void 
+static gboolean
 db_insert_way_name(way *w)
 {
-gchar *norm;
-
 if (!w->data)
-       return;
+       return TRUE;
 if (!w->data->name)
-       return;
+       return TRUE;
 
 way_names++;
 
@@ -622,62 +623,66 @@ sqlite3_bind_int(sql.insert_way_name, 1, w->id);
 sqlite3_bind_text(sql.insert_way_name, 2, w->data->name, -1, SQLITE_TRANSIENT);
 
 #ifdef TRANSLIT_NAMES
-norm=g_convert(w->data->name, -1, "ASCII//TRANSLIT//IGNORE", "utf8", NULL, NULL, NULL);
-if (norm && strcmp(w->data->name, norm)!=0) {
-       sqlite3_bind_text(sql.insert_way_name, 3, norm, -1, SQLITE_TRANSIENT);
+{
+       gchar *norm;
+       norm=g_convert(w->data->name, -1, "ASCII//TRANSLIT//IGNORE", "utf8", NULL, NULL, NULL);
+       if (norm && strcmp(w->data->name, norm)!=0) {
+               sqlite3_bind_text(sql.insert_way_name, 3, norm, -1, SQLITE_TRANSIENT);
+       }
+       if (norm)
+               g_free(norm);
 }
-if (norm)
-       g_free(norm);
 #endif
 
-db_exec(db,sql.insert_way_name);
+return db_exec(db,sql.insert_way_name);
 }
 
-static void
+static gboolean
 db_delete_way_names_nls(way *w)
 {
 sqlite3_bind_int(sql.delete_way_names_nls, 1, w->id);
-db_exec(db,sql.delete_way_names_nls);
+return db_exec(db,sql.delete_way_names_nls);
 }
 
-static void 
+static gboolean 
 db_insert_way_pc(way *w)
 {
 if (!w->data)
-       return;
+       return TRUE;
 if (!w->data->postal_code)
-       return;
+       return TRUE;
 
 sqlite3_bind_int(sql.insert_way_pc, 1, w->id);
 sqlite3_bind_text(sql.insert_way_pc, 2, w->data->postal_code, -1, SQLITE_TRANSIENT);
 
-db_exec(db,sql.insert_way_pc);
+return db_exec(db,sql.insert_way_pc);
 }
 
-static void
+static gboolean
 db_delete_way_pc(way *w)
 {
 sqlite3_bind_int(sql.delete_way_pc, 1, w->id);
-db_exec(db,sql.delete_way_pc);
+return db_exec(db,sql.delete_way_pc);
 }
 
 static void
 db_insert_way_names_nls_cb(gpointer key, gpointer value, gpointer user_data)
 {
-gchar *norm;
-
 way *w=(way *)user_data;
 
 sqlite3_bind_int(sql.insert_way_names_nls, 1, w->id);
 sqlite3_bind_text(sql.insert_way_names_nls, 2, (gchar *)key, -1, SQLITE_TRANSIENT);
 sqlite3_bind_text(sql.insert_way_names_nls, 3, (gchar *)value, -1, SQLITE_TRANSIENT);
 #ifdef TRANSLIT_NAMES
-norm=g_convert((gchar *value), -1, "ASCII//TRANSLIT//IGNORE", "utf8", NULL, NULL, NULL);
-if (norm && strcmp((gchar *)value, norm)!=0) {
-       sqlite3_bind_text(sql.insert_way_names_nls, 4, norm, -1, SQLITE_TRANSIENT);
+{
+       gchar *norm;
+       norm=g_convert((gchar *value), -1, "ASCII//TRANSLIT//IGNORE", "utf8", NULL, NULL, NULL);
+       if (norm && strcmp((gchar *)value, norm)!=0) {
+               sqlite3_bind_text(sql.insert_way_names_nls, 4, norm, -1, SQLITE_TRANSIENT);
+       }
+       if (norm)
+               g_free(norm);
 }
-if (norm)
-       g_free(norm);
 #endif
 db_exec(db,sql.insert_way_names_nls);
 }
@@ -731,13 +736,6 @@ if (w->data) {
 
 print_way(w);
 
-/* Get middle node, use it as way location */
-ncnt=g_slist_length(w->nodes);
-if (ncnt>1)
-       wmn=g_slist_nth_data(w->nodes, ncnt/2);
-else
-       wmn=0;
-
 sqlite3_bind_int(sql.insert_way_data, 1, w->id);
 sqlite3_bind_int(sql.insert_way_data, 2, w->ncnt);
 sqlite3_bind_int(sql.insert_way_data, 3, w->type);
@@ -747,11 +745,17 @@ if (w->data) {
        sqlite3_bind_int(sql.insert_way_data, 6, w->data->isin_c);
        sqlite3_bind_int(sql.insert_way_data, 7, w->data->isin_p);
 }
-if (wmn) {
-       sqlite3_bind_double(sql.insert_way_data, 8, wmn->lat);
-       sqlite3_bind_double(sql.insert_way_data, 9, wmn->lon);
-} else {
-       g_printerr("Failed to get way location node!\n");
+
+/* Get middle node, use it as a rough way location */
+ncnt=g_slist_length(w->nodes);
+if (ncnt>1) {
+       wmn=g_slist_nth_data(w->nodes, ncnt/2);
+       if (wmn) {
+               sqlite3_bind_double(sql.insert_way_data, 8, wmn->lat);
+               sqlite3_bind_double(sql.insert_way_data, 9, wmn->lon);
+       } else {
+               g_printerr("Failed to get way middlepoint node for location information!\n");
+       }
 }
 
 db_exec(db,sql.insert_way_data);
@@ -872,11 +876,7 @@ if (n==NULL)
        return;
 if (n->data!=NULL) 
        return;
-n->data=g_slice_new(node_data);
-n->data->name=NULL;
-n->data->url=NULL;
-n->data->desc=NULL;
-n->data->postal_code=NULL;
+n->data=g_slice_new0(node_data);
 n->type=NODE_PLAIN;
 noded_cnt++;
 }
@@ -904,12 +904,11 @@ osm_new_node(gint id, gdouble lat, gdouble lon)
 {
 node *n=NULL;
 
-n=g_slice_new(node);
+n=g_slice_new0(node);
 g_assert(n);
 n->id=id;
 n->lat=lat;
 n->lon=lon;
-n->data=(node_data *)NULL;
 return n;
 }
 
@@ -926,12 +925,7 @@ osm_find_node(guint32 nid)
 node *n;
 
 g_assert(osm_nodes);
-n=g_hash_table_lookup(osm_nodes, GINT_TO_POINTER(nid));
-#if 0
-if (!n)
-       g_printerr("ERROR: Node %d not found!\n", nid);
-#endif
-return n;
+return g_hash_table_lookup(osm_nodes, GINT_TO_POINTER(nid));
 }
 
 static void
@@ -942,17 +936,10 @@ if (w==NULL)
 if (w->data!=NULL) 
        return;
 
-w->data=g_slice_new(way_data);
-w->data->name=NULL;
-w->data->names=NULL;
-w->data->ref=NULL;
-w->data->int_ref=NULL;
-w->data->postal_code=NULL;
-w->data->layer=0;
-w->data->speed=0;
+w->data=g_slice_new0(way_data);
 }
 
-void
+static void
 osm_free_way_data(way *w)
 {
 g_assert(w);
@@ -973,19 +960,23 @@ osm_new_way(gint id)
 {
 way *w;
 
-w=g_slice_new(way);
+w=g_slice_new0(way);
 g_assert(w);
 w->id=id;
-w->nodes=NULL;
 w->type=WAY_UNWAYED;
-w->data=NULL;
-w->ncnt=0;
-w->flags=0;
 
 /* Add to list of ways */
 return w;
 }
 
+static void
+osm_free_way(way *w)
+{
+if (w->nodes)
+       g_slist_free(w->nodes);
+g_slice_free(way, w);
+}
+
 static void
 osm_way_add_to_list(way *w)
 {
@@ -1063,7 +1054,7 @@ while (*place!=NULL) {
 return 0;
 }
 
-guint32
+static guint32
 osm_find_way_place(way *w, node_type_t nt)
 {
 gchar **isin;
@@ -1117,8 +1108,10 @@ node *n=(node *)value;
 
 dbnode_cnt++;
 db_insert_node(n);
-if (dbnode_cnt % 26214==0)
-       g_printf("\rNodes: %f%%\n",((float)dbnode_cnt/(float)node_cnt)*100);
+if (dbnode_cnt % 20000==0)
+       g_printf("\rNodes: %f%% (%u/%u)\n",
+               ((float)dbnode_cnt/(float)(node_cnt-node_skip_cnt))*100,
+               dbnode_cnt, node_cnt);
 }
 
 /**
@@ -1162,7 +1155,7 @@ osm_planet_poi_clear_nodes(void)
 g_print("Removing old OSM POIs...\n");
 db_transaction_begin(db);
 sqlite3_step(sql.delete_osm_poi);
-sqlite3_step(sql.delete_place);
+sqlite3_step(sql.delete_places);
 return db_transaction_commit(db);
 }
 
@@ -1178,17 +1171,19 @@ return db_transaction_commit(db);
 
 /*********************************************************************/
 
-static void
+static gboolean
 osm_planet_clear_nodes(void)
 {
-g_print("Clearing old nodes\n");
+g_print("Clearing old nodes...\n");
+db_transaction_begin(db);
 sqlite3_step(sql.delete_nodes);
+return db_transaction_commit(db);
 }
 
 static gboolean
 osm_planet_save_nodes(void)
 {
-g_print("Storing nodes\n");
+g_print("Storing new nodes...\n");
 db_transaction_begin(db);
 g_hash_table_foreach(osm_nodes, osm_node_save_node, NULL);
 return db_transaction_commit(db);
@@ -1200,9 +1195,13 @@ static void
 osm_way_save(way *value, gpointer user_data)
 {
 dbway_cnt++;
+db_transaction_begin(db);
 db_insert_way(value);
-if (dbway_cnt % 16384==0 && dbway_cnt>0) {
-               g_printf("\rWays: %f%%\n",(((float)dbway_cnt/(float)way_cnt)*100));
+db_transaction_commit(db);
+if (dbway_cnt % 15000==0 && dbway_cnt>0) {
+               g_printf("\rWays: %f%% (%u/%u)\n",
+                       (((float)dbway_cnt/(float)way_cnt)*100),
+                       dbway_cnt, way_cnt);
                print_way(value);
 }
 }
@@ -1210,20 +1209,20 @@ if (dbway_cnt % 16384==0 && dbway_cnt>0) {
 static void
 osm_planet_clear_ways(void)
 {
-g_print("Clearing old data\n");
+g_print("Clearing old way data...\n");
+db_transaction_begin(db);
 sqlite3_step(sql.delete_way);
 sqlite3_step(sql.delete_way_name);
 sqlite3_step(sql.delete_way_ref);
 sqlite3_step(sql.delete_way_n2n);
+db_transaction_commit(db);
 }
 
 static gboolean
 osm_planet_save_ways(void)
 {
 g_print("Inserting new ways\n");
-db_transaction_begin(db);
 g_slist_foreach(osm_ways, osm_way_save, NULL);
-return db_transaction_commit(db);
 }
 
 /*********************************************************************/
@@ -1356,6 +1355,23 @@ switch (t) {
 }
 }
 
+#define GET_NODE_KEY(key, nfield) { \
+       gchar *_kv; \
+       _kv=g_hash_table_lookup(osm_node_tags, key); \
+       if (_kv) { \
+               if (!nfield) { \
+                       nfield=g_strstrip(g_utf8_normalize(_kv, -1, G_NORMALIZE_ALL_COMPOSE)); \
+               } else { \
+                       gchar *_tmp=nfield; \
+                       gchar *_norm=g_utf8_normalize(_kv, -1, G_NORMALIZE_ALL_COMPOSE); \
+                       nfield=g_strdup_printf("%s %s", _tmp, g_strstrip(_norm)); \
+                       g_free(_tmp); \
+                       g_free(_norm); \
+               } \
+       } \
+}
+       
+
 static void
 _osm_tag_end(void *userData, const char *name)
 {
@@ -1366,8 +1382,9 @@ t=check_tag(name);
 switch (t) {
        case IN_NODE_TAG:
 
-               if (node_cnt % 262140==0) {
-                       g_printf("Nodes: %d of %d, POIs: %d, Outside box: %d\n", node_cnt-node_skip_cnt, node_cnt, noded_cnt, node_skip_cnt);
+               if (node_cnt % 25000==0) {
+                       g_printf("Nodes: %u of %u, POIs: %u, Outside box: %u\n", 
+                               node_cnt-node_skip_cnt, node_cnt, noded_cnt, node_skip_cnt);
                }
 
                if (!osm_node_tags)
@@ -1390,8 +1407,7 @@ switch (t) {
                 * - Places (for is_in)
                 * - ...
                 */
-               if ((osm_node_check_box(cnode->lat, cnode->lon)==FALSE) && 
-                               (cnode->type<NODE_PLACE_START)) {
+               if ((osm_node_check_box(cnode->lat, cnode->lon)==FALSE) && (cnode->type<NODE_PLACE_START)) {
                        osm_free_node_data(cnode);
                        osm_free_node(cnode);
                        g_hash_table_destroy(osm_node_tags);
@@ -1406,12 +1422,11 @@ switch (t) {
                        v=g_hash_table_lookup(osm_node_tags, "name");
                        if (v)
                                cnode->data->name=g_strstrip(g_utf8_normalize(v, -1, G_NORMALIZE_ALL_COMPOSE));
-                       v=g_hash_table_lookup(osm_node_tags, "note");
-                       if (v)
-                               cnode->data->desc=g_strstrip(g_strdup(v));
-                       v=g_hash_table_lookup(osm_node_tags, "postal_code");
-                       if (v)
-                               cnode->data->postal_code=g_strstrip(g_strdup(v));
+
+                       GET_NODE_KEY("description", cnode->data->desc);
+                       GET_NODE_KEY("note", cnode->data->desc);
+                       GET_NODE_KEY("postal_code", cnode->data->postal_code);
+                       GET_NODE_KEY("address", cnode->data->desc);
 
                        /* Links */
                        v=g_hash_table_lookup(osm_node_tags, "url");
@@ -1512,10 +1527,12 @@ switch (t) {
                if (v)
                        cway->data->postal_code=g_strdup(v);
 
-               /* XXX: somehow handle the silly -1 'reversed' oneway */
                v=g_hash_table_lookup(osm_way_tags, "oneway");
-               if (v)
+               if (v) {
                        cway->flags|=W_ONEWAY;
+                       if (strcmp(v, "-1")==0)
+                               cway->nodes=g_slist_reverse(cway->nodes);
+               }
 
                v=g_hash_table_lookup(osm_way_tags, "noexit");
                if (v)
@@ -1528,11 +1545,9 @@ switch (t) {
                if (v)
                        cway->data->speed=atoi(v);
 
-#if 0
                v=g_hash_table_lookup(osm_way_tags, "layer");
                if (v)
                        cway->data->layer=atoi(v);
-#endif
 
                v=g_hash_table_lookup(osm_way_tags, "junction");
                if (v && strcasecmp(v,"roundabout")==0) {
@@ -1564,6 +1579,8 @@ switch (t) {
 
                if (cway->id!=0)
                        osm_way_add_to_list(cway);
+               else 
+                       osm_free_way(cway);
 
                cway=NULL;
                g_hash_table_destroy(osm_way_tags);
@@ -1607,7 +1624,6 @@ g_hash_table_destroy(osm_place_region);
 g_hash_table_destroy(osm_node_isin);
 }
 
-
 /************************************************************************/
 
 static gint
@@ -1649,12 +1665,12 @@ storage_free();
 }
 
 gboolean
-osm_planet_parse_buffer(gchar *buffer, size_t r)
+osm_planet_parse_buffer(const gchar *buffer, size_t r)
 {
 if (XML_Parse(xp, buffer, r, r>0 ? 0:1) == XML_STATUS_ERROR) {
        g_printerr("Parse error at line %d:\n%s\n",
-       XML_GetCurrentLineNumber(xp),
-       XML_ErrorString(XML_GetErrorCode(xp)));
+               (gint)XML_GetCurrentLineNumber(xp),
+               XML_ErrorString(XML_GetErrorCode(xp)));
        return FALSE;
 }
 return TRUE;
@@ -1700,6 +1716,10 @@ fclose(f);
 return res;
 }
 
+/**
+ * Set up bounding box for import.
+ *
+ */
 void
 osm_import_set_bbox(gboolean use_bb, gdouble latmin, gdouble lonmin, gdouble latmax, gdouble lonmax)
 {
@@ -1712,6 +1732,20 @@ g_printf("Skipping data outside of box: %f,%f - %f,%f\n",
        bbox.lat_min, bbox.lon_min,     bbox.lat_max, bbox.lon_max);
 }
 
+static void
+osm_print_import_stats(void)
+{
+g_printf("Total nodes %d, POIs: %d and Ways %d.\n",    node_cnt, noded_cnt, way_cnt);
+g_printf("Cities/Towns: %d\n", g_hash_table_size(osm_place_city));
+g_printf("Villages/Hamlets: %d\n", g_hash_table_size(osm_place_village));
+g_printf("Suburbs: %d\n", g_hash_table_size(osm_place_suburb));
+g_printf("Nodes: %d\n", g_hash_table_size(osm_nodes));
+}
+
+/**
+ * Simple helper to do all preparations and importing from planet -> database
+ *
+ */
 gboolean
 osm_import(const gchar *planet, const gchar *database)
 {
@@ -1720,9 +1754,21 @@ if (db_connect(&db, database)!=TRUE) {
        return FALSE;
 }
 
-db_create_tables(db);
-db_create_indexes(db);
-db_prepare(db);
+/* Set some sqlite PRAGMAs to speed up import */
+sqlite3_exec(db, "PRAGMA cache_size=16000;", NULL, NULL, NULL);
+sqlite3_exec(db, "PRAGMA locking_mode=EXCLUSIVE;", NULL, NULL, NULL);
+sqlite3_exec(db, "PRAGMA journal_mode=PERSIST;", NULL, NULL, NULL);
+sqlite3_exec(db, "PRAGMA synchronous=OFF;", NULL, NULL, NULL);
+
+if (!osm_db_create(db)) {
+       g_printerr("Failed to create osm tables or indexes\n");
+       return FALSE;
+}
+
+if (!osm_db_prepare(db)) {
+       g_printerr("Failed to prepare sql statements\n");
+       return FALSE;
+}
 
 osm_planet_parser_init();
 
@@ -1731,16 +1777,82 @@ if (osm_planet_parse_file(planet)==FALSE) {
        return FALSE;
 }
 
-g_printf("Total nodes %d, POIs: %d and Ways %d.\n",    node_cnt, noded_cnt, way_cnt);
-g_printf("Cities/Towns: %d\n", g_hash_table_size(osm_place_city));
-g_printf("Villages/Hamlets: %d\n", g_hash_table_size(osm_place_village));
-g_printf("Suburbs: %d\n", g_hash_table_size(osm_place_suburb));
-g_printf("Nodes: %d\n", g_hash_table_size(osm_nodes));
+osm_print_import_stats();
 
 osm_planet_save_all_nodes();
 osm_planet_save_all_ways();
 osm_planet_parser_deinit();
+db_finalize();
 db_close(&db);
+g_printf("All done.\n");
+return TRUE;
+}
+
+static gpointer 
+osm_import_thread(gpointer user_data)
+{
+gboolean r;
+osm_import_data_req *req=(osm_import_data_req *)user_data;
+
+g_assert(req);
+g_assert(req->planet);
+g_assert(req->db);
+
+osm_import_progress_cb=req->progress_cb!=NULL ? req->progress_cb : NULL;
+
+r=osm_import(req->planet, req->db);
+g_debug("OSM import result: %d", r);
+
+g_free(req->planet);
+g_free(req->db);
+
+if (req->done_cb!=NULL)
+       g_idle_add(req->done_cb, GINT_TO_POINTER(r==TRUE ? 0 : 1));
+
+return r==TRUE ? 0 : 1;
+}
+
+/**
+ * Helper to start an import in the background using a thread.
+ *
+ * Two callback can be given, one for progress feedback and one when the operation is done.
+ * Done callback must call the join function.
+ * Only one import thread can run at a time.
+ *
+ */
+gboolean 
+osm_import_bg(const gchar *planet, const gchar *database, GSourceFunc progress_cb, GSourceFunc done_cb)
+{
+GError *error=NULL;
+
+g_return_val_if_fail(import_thread==NULL, FALSE);
+
+osm_import_req.planet=g_strdup(planet);
+osm_import_req.db=g_strdup(database);
+osm_import_req.progress_cb=progress_cb;
+osm_import_req.done_cb=done_cb;
+
+import_thread=g_thread_create(osm_import_thread, &osm_import_req, TRUE, &error);
+if (import_thread==NULL) {
+       g_free(osm_import_req.planet);
+       g_free(osm_import_req.db);
+       g_printerr("Import thread creation failed.\n");
+       return FALSE;
+}
+if (osm_import_progress_cb!=NULL)
+       import_sid=g_timeout_add(1000, osm_import_progress_cb, NULL);
 return TRUE;
 }
 
+gint
+osm_import_join_bg(void)
+{
+gint ret;
+g_assert(import_thread!=NULL);
+
+if (import_sid!=0)
+       g_source_remove(import_sid);
+ret=g_thread_join(import_thread);
+import_thread=NULL;
+return ret;
+}