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) {
48 fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
52 pg_prepare_params[0] = PG_OID_INT4;
53 res = PQprepare(conn, "index_sectors",
54 "select geometry_sector,count(*) from placex where rank_search = $1 and indexed = true group by geometry_sector order by geometry_sector",
55 1, pg_prepare_params);
56 if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
59 pg_prepare_params[0] = PG_OID_INT4;
60 pg_prepare_params[1] = PG_OID_INT4;
61 res = PQprepare(conn, "index_sector_places",
62 "select place_id from placex where rank_search = $1 and geometry_sector = $2",
63 2, pg_prepare_params);
64 if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
67 nominatim_exportCreatePreparedQueries(conn);
69 // Create the output file
70 writer = nominatim_exportXMLStart(structuredoutputfile);
72 for (rank = rank_min; rank <= rank_max; rank++)
74 printf("Starting rank %d\n", rank);
76 paramRank = PGint32(rank);
77 paramValues[0] = (char *)¶mRank;
78 paramLengths[0] = sizeof(paramRank);
80 resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
81 if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
83 fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
87 if (PQftype(resSectors, 0) != PG_OID_INT4)
89 fprintf(stderr, "Sector value has unexpected type\n");
93 if (PQftype(resSectors, 1) != PG_OID_INT8)
95 fprintf(stderr, "Sector value has unexpected type\n");
101 for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
103 sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
105 // Get all the place_id's for this sector
106 paramRank = PGint32(rank);
107 paramValues[0] = (char *)¶mRank;
108 paramLengths[0] = sizeof(paramRank);
110 paramSector = PGint32(sector);
111 paramValues[1] = (char *)¶mSector;
112 paramLengths[1] = sizeof(paramSector);
114 resPlaces = PQexecPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
115 if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
117 fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
121 if (PQftype(resPlaces, 0) != PG_OID_INT8)
123 fprintf(stderr, "Place_id value has unexpected type\n");
128 tuples = PQntuples(resPlaces);
129 for(i = 0; i < tuples; i++)
131 nominatim_exportPlace(PGint64(*((uint64_t *)PQgetvalue(resPlaces, i, 0))), conn, writer, NULL);
133 if (rankTotalDone%1000 == 0) printf("Done %i (k)\n", rankTotalDone/1000);
140 nominatim_exportXMLEnd(writer);
145 void nominatim_exportCreatePreparedQueries(PGconn * conn)
147 Oid pg_prepare_params[2];
150 pg_prepare_params[0] = PG_OID_INT8;
151 res = PQprepare(conn, "placex_details",
152 "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",
153 1, pg_prepare_params);
154 if (PQresultStatus(res) != PGRES_COMMAND_OK)
156 fprintf(stderr, "Error preparing placex_details: %s", PQerrorMessage(conn));
161 pg_prepare_params[0] = PG_OID_INT8;
162 res = PQprepare(conn, "placex_address",
163 "select osm_type,osm_id,class,type,distance,cached_rank_address from place_addressline join placex on (address_place_id = placex.place_id) where isaddress and place_addressline.place_id = $1 and address_place_id != place_addressline.place_id order by cached_rank_address asc",
164 1, pg_prepare_params);
165 if (PQresultStatus(res) != PGRES_COMMAND_OK)
167 fprintf(stderr, "Error preparing placex_address: %s", PQerrorMessage(conn));
172 pg_prepare_params[0] = PG_OID_INT8;
173 res = PQprepare(conn, "placex_names",
174 "select (each(name)).key,(each(name)).value from (select name as name from placex where place_id = $1) as x",
175 1, pg_prepare_params);
176 if (PQresultStatus(res) != PGRES_COMMAND_OK)
178 fprintf(stderr, "Error preparing placex_names: %s", PQerrorMessage(conn));
184 xmlTextWriterPtr nominatim_exportXMLStart(const char *structuredoutputfile)
186 xmlTextWriterPtr writer;
188 writer = xmlNewTextWriterFilename(structuredoutputfile, 0);
191 fprintf(stderr, "Unable to open %s\n", structuredoutputfile);
194 xmlTextWriterSetIndent(writer, 1);
195 if (xmlTextWriterStartDocument(writer, NULL, "UTF8", NULL) < 0)
197 fprintf(stderr, "xmlTextWriterStartDocument failed\n");
200 if (xmlTextWriterStartElement(writer, BAD_CAST "osmStructured") < 0)
202 fprintf(stderr, "xmlTextWriterStartElement failed\n");
205 if (xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "0.1") < 0)
207 fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
210 if (xmlTextWriterWriteAttribute(writer, BAD_CAST "generator", BAD_CAST "Nominatim") < 0)
212 fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
215 if (xmlTextWriterStartElement(writer, BAD_CAST "add") < 0)
217 fprintf(stderr, "xmlTextWriterStartElement failed\n");
224 void nominatim_exportXMLEnd(xmlTextWriterPtr writer)
227 if (xmlTextWriterEndElement(writer) < 0)
229 fprintf(stderr, "xmlTextWriterEndElement failed\n");
232 // End <osmStructured>
233 if (xmlTextWriterEndElement(writer) < 0)
235 fprintf(stderr, "xmlTextWriterEndElement failed\n");
238 if (xmlTextWriterEndDocument(writer) < 0)
240 fprintf(stderr, "xmlTextWriterEndDocument failed\n");
243 xmlFreeTextWriter(writer);
247 * Requirements: the prepared queries must exist
249 void nominatim_exportPlace(uint64_t place_id, PGconn * conn, xmlTextWriterPtr writer, pthread_mutex_t * writer_mutex)
253 PGresult * resAddress;
257 const char * paramValues[1];
260 uint64_t paramPlaceID;
263 paramPlaceID = PGint64(place_id);
264 paramValues[0] = (char *)¶mPlaceID;
265 paramLengths[0] = sizeof(paramPlaceID);
268 res = PQexecPrepared(conn, "placex_details", 1, paramValues, paramLengths, paramFormats, 0);
269 if (PQresultStatus(res) != PGRES_TUPLES_OK)
271 fprintf(stderr, "placex_details: SELECT failed: %s", PQerrorMessage(conn));
276 resNames = PQexecPrepared(conn, "placex_names", 1, paramValues, paramLengths, paramFormats, 0);
277 if (PQresultStatus(resNames) != PGRES_TUPLES_OK)
279 fprintf(stderr, "placex_names: SELECT failed: %s", PQerrorMessage(conn));
284 resAddress = PQexecPrepared(conn, "placex_address", 1, paramValues, paramLengths, paramFormats, 0);
285 if (PQresultStatus(resAddress) != PGRES_TUPLES_OK)
287 fprintf(stderr, "placex_address: SELECT failed: %s", PQerrorMessage(conn));
292 if (writer_mutex) pthread_mutex_lock( writer_mutex );
294 xmlTextWriterStartElement(writer, BAD_CAST "feature");
295 xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "place_id", "%li", place_id);
296 xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(res, 0, 0));
297 xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(res, 0, 1));
298 xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(res, 0, 2));
299 xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(res, 0, 3));
300 xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(res, 0, 9));
301 xmlTextWriterWriteAttribute(writer, BAD_CAST "importance", BAD_CAST PQgetvalue(res, 0, 10));
303 if (PQgetvalue(res, 0, 4) && strlen(PQgetvalue(res, 0, 4)))
305 xmlTextWriterStartElement(writer, BAD_CAST "names");
307 for(i = 0; i < PQntuples(resNames); i++)
309 xmlTextWriterStartElement(writer, BAD_CAST "name");
310 xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resNames, i, 0));
311 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(resNames, i, 1));
312 xmlTextWriterEndElement(writer);
315 xmlTextWriterEndElement(writer);
318 if (PQgetvalue(res, 0, 5) && strlen(PQgetvalue(res, 0, 5)))
320 xmlTextWriterStartElement(writer, BAD_CAST "houseNumber");
321 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 5));
322 xmlTextWriterEndElement(writer);
325 if (PQgetvalue(res, 0, 8) && strlen(PQgetvalue(res, 0, 8)))
327 xmlTextWriterStartElement(writer, BAD_CAST "adminLevel");
328 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 8));
329 xmlTextWriterEndElement(writer);
332 if (PQgetvalue(res, 0, 6) && strlen(PQgetvalue(res, 0, 6)))
334 xmlTextWriterStartElement(writer, BAD_CAST "countryCode");
335 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 6));
336 xmlTextWriterEndElement(writer);
339 if (PQntuples(resAddress)> 0)
341 xmlTextWriterStartElement(writer, BAD_CAST "address");
342 for(i = 0; i < PQntuples(resAddress); i++)
344 xmlTextWriterStartElement(writer, BAD_CAST getRankLabel(atoi(PQgetvalue(resAddress, i, 5))));
345 xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(resAddress, i, 5));
346 xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resAddress, i, 0));
347 xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(resAddress, i, 1));
348 xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(resAddress, i, 2));
349 xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(resAddress, i, 3));
350 xmlTextWriterWriteAttribute(writer, BAD_CAST "distance", BAD_CAST PQgetvalue(resAddress, i, 4));
351 xmlTextWriterEndElement(writer);
353 xmlTextWriterEndElement(writer);
356 xmlTextWriterStartElement(writer, BAD_CAST "osmGeometry");
357 xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 7));
358 xmlTextWriterEndElement(writer);
360 xmlTextWriterEndElement(writer); // </feature>
362 if (writer_mutex) pthread_mutex_unlock( writer_mutex );
369 const char * getRankLabel(int rank)
407 return "neighborhood";