15 #include "nominatim.h"
17 #include "postgresql.h"
21 void nominatim_export(int rank_min, int rank_max, const char *conninfo, const char *structuredoutputfile)
23 xmlTextWriterPtr writer;
29 PGresult * resSectors;
37 const char *paramValues[2];
44 Oid pg_prepare_params[2];
46 conn = PQconnectdb(conninfo);
47 if (PQstatus(conn) != CONNECTION_OK)
49 fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
53 pg_prepare_params[0] = PG_OID_INT4;
54 res = PQprepare(conn, "index_sectors",
55 "select geometry_sector,count(*) from placex where rank_search = $1 and indexed_status = 0 group by geometry_sector order by geometry_sector",
56 1, pg_prepare_params);
57 if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
60 pg_prepare_params[0] = PG_OID_INT4;
61 pg_prepare_params[1] = PG_OID_INT4;
62 res = PQprepare(conn, "index_sector_places",
63 "select place_id from placex where rank_search = $1 and geometry_sector = $2",
64 2, pg_prepare_params);
65 if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
68 nominatim_exportCreatePreparedQueries(conn);
70 // Create the output file
71 writer = nominatim_exportXMLStart(structuredoutputfile);
73 for (rank = rank_min; rank <= rank_max; rank++)
75 printf("Starting rank %d\n", rank);
77 paramRank = PGint32(rank);
78 paramValues[0] = (char *)¶mRank;
79 paramLengths[0] = sizeof(paramRank);
81 resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
82 if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
84 fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
88 if (PQftype(resSectors, 0) != PG_OID_INT4)
90 fprintf(stderr, "Sector value has unexpected type\n");
94 if (PQftype(resSectors, 1) != PG_OID_INT8)
96 fprintf(stderr, "Sector value has unexpected type\n");
102 for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
104 sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
106 // Get all the place_id's for this sector
107 paramRank = PGint32(rank);
108 paramValues[0] = (char *)¶mRank;
109 paramLengths[0] = sizeof(paramRank);
111 paramSector = PGint32(sector);
112 paramValues[1] = (char *)¶mSector;
113 paramLengths[1] = sizeof(paramSector);
115 resPlaces = PQexecPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
116 if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
118 fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
122 if (PQftype(resPlaces, 0) != PG_OID_INT4)
124 fprintf(stderr, "Place_id value has unexpected type\n");
129 tuples = PQntuples(resPlaces);
130 for (i = 0; i < tuples; i++)
132 nominatim_exportPlace(PGint32(*((uint32_t *)PQgetvalue(resPlaces, i, 0))), conn, writer, NULL);
134 if (rankTotalDone%1000 == 0) printf("Done %i (k)\n", rankTotalDone/1000);
141 nominatim_exportXMLEnd(writer);
146 void nominatim_exportCreatePreparedQueries(PGconn * conn)
148 Oid pg_prepare_params[2];
151 pg_prepare_params[0] = PG_OID_INT8;
152 res = PQprepare(conn, "placex_details",
153 "select osm_type, osm_id, class, type, name, housenumber, country_code, ST_AsText(geometry), admin_level, rank_address, rank_search from placex where place_id = $1",
154 1, pg_prepare_params);
155 if (PQresultStatus(res) != PGRES_COMMAND_OK)
157 fprintf(stderr, "Error preparing placex_details: %s", PQerrorMessage(conn));
162 pg_prepare_params[0] = PG_OID_INT8;
163 res = PQprepare(conn, "placex_address",
164 "select osm_type,osm_id,class,type,distance,cached_rank_address,isaddress from place_addressline join placex on (address_place_id = placex.place_id) where place_addressline.place_id = $1 and address_place_id != place_addressline.place_id order by cached_rank_address asc,osm_type,osm_id",
165 1, pg_prepare_params);
166 if (PQresultStatus(res) != PGRES_COMMAND_OK)
168 fprintf(stderr, "Error preparing placex_address: %s", PQerrorMessage(conn));
173 pg_prepare_params[0] = PG_OID_INT8;
174 res = PQprepare(conn, "placex_names",
175 "select (each(name)).key,(each(name)).value from (select name from placex where place_id = $1) as x order by (each(name)).key",
176 1, pg_prepare_params);
177 if (PQresultStatus(res) != PGRES_COMMAND_OK)
179 fprintf(stderr, "Error preparing placex_names: %s", PQerrorMessage(conn));
184 pg_prepare_params[0] = PG_OID_INT8;
185 res = PQprepare(conn, "placex_extratags",
186 "select (each(extratags)).key,(each(extratags)).value from (select extratags from placex where place_id = $1) as x order by (each(extratags)).key",
187 1, pg_prepare_params);
188 if (PQresultStatus(res) != PGRES_COMMAND_OK)
190 fprintf(stderr, "Error preparing placex_extratags: %s", PQerrorMessage(conn));
196 xmlTextWriterPtr nominatim_exportXMLStart(const char *structuredoutputfile)
198 xmlTextWriterPtr writer;
200 writer = xmlNewTextWriterFilename(structuredoutputfile, 0);
203 fprintf(stderr, "Unable to open %s\n", structuredoutputfile);
206 xmlTextWriterSetIndent(writer, 1);
207 if (xmlTextWriterStartDocument(writer, NULL, "UTF8", NULL) < 0)
209 fprintf(stderr, "xmlTextWriterStartDocument failed\n");
212 if (xmlTextWriterStartElement(writer, BAD_CAST "osmStructured") < 0)
214 fprintf(stderr, "xmlTextWriterStartElement failed\n");
217 if (xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "0.1") < 0)
219 fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
222 if (xmlTextWriterWriteAttribute(writer, BAD_CAST "generator", BAD_CAST "Nominatim") < 0)
224 fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
227 if (xmlTextWriterStartElement(writer, BAD_CAST "add") < 0)
229 fprintf(stderr, "xmlTextWriterStartElement failed\n");
236 void nominatim_exportXMLEnd(xmlTextWriterPtr writer)
239 if (xmlTextWriterEndElement(writer) < 0)
241 fprintf(stderr, "xmlTextWriterEndElement failed\n");
244 // End <osmStructured>
245 if (xmlTextWriterEndElement(writer) < 0)
247 fprintf(stderr, "xmlTextWriterEndElement failed\n");
250 if (xmlTextWriterEndDocument(writer) < 0)
252 fprintf(stderr, "xmlTextWriterEndDocument failed\n");
255 xmlFreeTextWriter(writer);
259 * Requirements: the prepared queries must exist
261 void nominatim_exportPlace(uint64_t place_id, PGconn * conn, xmlTextWriterPtr writer, pthread_mutex_t * writer_mutex)
265 PGresult * resAddress;
266 PGresult * resExtraTags;
270 const char * paramValues[1];
273 uint64_t paramPlaceID;
276 paramPlaceID = PGint64(place_id);
277 paramValues[0] = (char *)¶mPlaceID;
278 paramLengths[0] = sizeof(paramPlaceID);
281 res = PQexecPrepared(conn, "placex_details", 1, paramValues, paramLengths, paramFormats, 0);
282 if (PQresultStatus(res) != PGRES_TUPLES_OK)
284 fprintf(stderr, "placex_details: SELECT failed: %s", PQerrorMessage(conn));
289 resNames = PQexecPrepared(conn, "placex_names", 1, paramValues, paramLengths, paramFormats, 0);
290 if (PQresultStatus(resNames) != PGRES_TUPLES_OK)
292 fprintf(stderr, "placex_names: SELECT failed: %s", PQerrorMessage(conn));
297 resAddress = PQexecPrepared(conn, "placex_address", 1, paramValues, paramLengths, paramFormats, 0);
298 if (PQresultStatus(resAddress) != PGRES_TUPLES_OK)
300 fprintf(stderr, "placex_address: SELECT failed: %s", PQerrorMessage(conn));
305 resExtraTags = PQexecPrepared(conn, "placex_extratags", 1, paramValues, paramLengths, paramFormats, 0);
306 if (PQresultStatus(resExtraTags) != PGRES_TUPLES_OK)
308 fprintf(stderr, "placex_extratags: SELECT failed: %s", PQerrorMessage(conn));
309 PQclear(resExtraTags);
313 if (writer_mutex) pthread_mutex_lock( writer_mutex );
315 xmlTextWriterStartElement(writer, BAD_CAST "feature");
316 xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "place_id", "%li", place_id);
317 xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(res, 0, 0));
318 xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(res, 0, 1));
319 xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(res, 0, 2));
320 xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(res, 0, 3));
321 xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(res, 0, 9));
322 xmlTextWriterWriteAttribute(writer, BAD_CAST "importance", BAD_CAST PQgetvalue(res, 0, 10));
324 if (PQntuples(resNames))
326 xmlTextWriterStartElement(writer, BAD_CAST "names");
328 for (i = 0; i < PQntuples(resNames); i++)
330 xmlTextWriterStartElement(writer, BAD_CAST "name");
331 xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resNames, i, 0));
332 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(resNames, i, 1));
333 xmlTextWriterEndElement(writer);
336 xmlTextWriterEndElement(writer);
339 if (PQgetvalue(res, 0, 5) && strlen(PQgetvalue(res, 0, 5)))
341 xmlTextWriterStartElement(writer, BAD_CAST "houseNumber");
342 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 5));
343 xmlTextWriterEndElement(writer);
346 if (PQgetvalue(res, 0, 8) && strlen(PQgetvalue(res, 0, 8)))
348 xmlTextWriterStartElement(writer, BAD_CAST "adminLevel");
349 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 8));
350 xmlTextWriterEndElement(writer);
353 if (PQgetvalue(res, 0, 6) && strlen(PQgetvalue(res, 0, 6)))
355 xmlTextWriterStartElement(writer, BAD_CAST "countryCode");
356 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 6));
357 xmlTextWriterEndElement(writer);
360 if (PQntuples(resAddress) > 0)
362 xmlTextWriterStartElement(writer, BAD_CAST "address");
363 for (i = 0; i < PQntuples(resAddress); i++)
365 xmlTextWriterStartElement(writer, BAD_CAST getRankLabel(atoi(PQgetvalue(resAddress, i, 5))));
366 xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(resAddress, i, 5));
367 xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resAddress, i, 0));
368 xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(resAddress, i, 1));
369 xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(resAddress, i, 2));
370 xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(resAddress, i, 3));
371 xmlTextWriterWriteAttribute(writer, BAD_CAST "distance", BAD_CAST PQgetvalue(resAddress, i, 4));
372 xmlTextWriterWriteAttribute(writer, BAD_CAST "isaddress", BAD_CAST PQgetvalue(resAddress, i, 6));
373 xmlTextWriterEndElement(writer);
375 xmlTextWriterEndElement(writer);
378 if (PQntuples(resExtraTags))
380 xmlTextWriterStartElement(writer, BAD_CAST "tags");
382 for (i = 0; i < PQntuples(resExtraTags); i++)
384 xmlTextWriterStartElement(writer, BAD_CAST "tag");
385 xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resExtraTags, i, 0));
386 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(resExtraTags, i, 1));
387 xmlTextWriterEndElement(writer);
390 xmlTextWriterEndElement(writer);
394 xmlTextWriterStartElement(writer, BAD_CAST "osmGeometry");
395 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 7));
396 xmlTextWriterEndElement(writer);
398 xmlTextWriterEndElement(writer); // </feature>
400 if (writer_mutex) pthread_mutex_unlock( writer_mutex );
405 PQclear(resExtraTags);
408 const char * getRankLabel(int rank)
446 return "neighborhood";