extern int verbose;
+int mode = 0;
+
void nominatim_export(int rank_min, int rank_max, const char *conninfo, const char *structuredoutputfile)
{
xmlTextWriterPtr writer;
- int rankTotalDone;
+ int rankTotalDone;
- PGconn *conn;
- PGresult * res;
- PGresult * resSectors;
- PGresult * resPlaces;
+ PGconn *conn;
+ PGresult * res;
+ PGresult * resSectors;
+ PGresult * resPlaces;
- int rank;
- int i;
- int iSector;
+ int rank;
+ int i;
+ int iSector;
int tuples;
const char *paramValues[2];
Oid pg_prepare_params[2];
- conn = PQconnectdb(conninfo);
- if (PQstatus(conn) != CONNECTION_OK) {
+ conn = PQconnectdb(conninfo);
+ if (PQstatus(conn) != CONNECTION_OK)
+ {
fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_sectors",
- "select geometry_sector,count(*) from placex where rank_search = $1 and indexed = true group by geometry_sector order by geometry_sector",
- 1, pg_prepare_params);
+ "select geometry_sector,count(*) from placex where rank_search = $1 and indexed_status = 0 group by geometry_sector order by geometry_sector",
+ 1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
pg_prepare_params[0] = PG_OID_INT4;
pg_prepare_params[1] = PG_OID_INT4;
res = PQprepare(conn, "index_sector_places",
- "select place_id from placex where rank_search = $1 and geometry_sector = $2",
- 2, pg_prepare_params);
+ "select place_id from placex where rank_search = $1 and geometry_sector = $2",
+ 2, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
nominatim_exportCreatePreparedQueries(conn);
- // Create the output file
- writer = nominatim_exportXMLStart(structuredoutputfile);
+ // Create the output file
+ writer = nominatim_exportXMLStart(structuredoutputfile);
for (rank = rank_min; rank <= rank_max; rank++)
{
- printf("Starting rank %d\n", rank);
+ printf("Starting rank %d\n", rank);
paramRank = PGint32(rank);
paramValues[0] = (char *)¶mRank;
PQclear(resSectors);
exit(EXIT_FAILURE);
}
- if (PQftype(resSectors, 0) != PG_OID_INT4)
- {
+ if (PQftype(resSectors, 0) != PG_OID_INT4)
+ {
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
- }
- if (PQftype(resSectors, 1) != PG_OID_INT8)
- {
+ }
+ if (PQftype(resSectors, 1) != PG_OID_INT8)
+ {
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
- }
-
- rankTotalDone = 0;
- for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
- {
- sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
-
- // Get all the place_id's for this sector
- paramRank = PGint32(rank);
- paramValues[0] = (char *)¶mRank;
- paramLengths[0] = sizeof(paramRank);
- paramFormats[0] = 1;
- paramSector = PGint32(sector);
- paramValues[1] = (char *)¶mSector;
- paramLengths[1] = sizeof(paramSector);
- paramFormats[1] = 1;
- resPlaces = PQexecPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
- if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
- {
- fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
- PQclear(resPlaces);
- exit(EXIT_FAILURE);
- }
- if (PQftype(resPlaces, 0) != PG_OID_INT8)
- {
- fprintf(stderr, "Place_id value has unexpected type\n");
- PQclear(resPlaces);
- exit(EXIT_FAILURE);
- }
-
- tuples = PQntuples(resPlaces);
- for(i = 0; i < tuples; i++)
- {
- nominatim_exportPlace(PGint64(*((uint64_t *)PQgetvalue(resPlaces, i, 0))), conn, writer, NULL);
- rankTotalDone++;
- if (rankTotalDone%1000 == 0) printf("Done %i (k)\n", rankTotalDone/1000);
- }
+ }
+
+ rankTotalDone = 0;
+ for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
+ {
+ sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
+
+ // Get all the place_id's for this sector
+ paramRank = PGint32(rank);
+ paramValues[0] = (char *)¶mRank;
+ paramLengths[0] = sizeof(paramRank);
+ paramFormats[0] = 1;
+ paramSector = PGint32(sector);
+ paramValues[1] = (char *)¶mSector;
+ paramLengths[1] = sizeof(paramSector);
+ paramFormats[1] = 1;
+ resPlaces = PQexecPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
+ if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
+ {
+ fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
+ PQclear(resPlaces);
+ exit(EXIT_FAILURE);
+ }
+ if (PQftype(resPlaces, 0) != PG_OID_INT8)
+ {
+ fprintf(stderr, "Place_id value has unexpected type\n");
+ PQclear(resPlaces);
+ exit(EXIT_FAILURE);
+ }
+
+ tuples = PQntuples(resPlaces);
+ for (i = 0; i < tuples; i++)
+ {
+ nominatim_exportPlace(PGint64(*((uint64_t *)PQgetvalue(resPlaces, i, 0))), conn, writer, NULL, NULL);
+ rankTotalDone++;
+ if (rankTotalDone%1000 == 0) printf("Done %i (k)\n", rankTotalDone/1000);
+ }
PQclear(resPlaces);
- }
+ }
PQclear(resSectors);
}
void nominatim_exportCreatePreparedQueries(PGconn * conn)
{
Oid pg_prepare_params[2];
- PGresult * res;
+ PGresult * res;
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(conn, "placex_details",
- "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",
- 1, pg_prepare_params);
+ "select placex.osm_type, placex.osm_id, placex.class, placex.type, placex.name, placex.housenumber, placex.country_code, ST_AsText(placex.geometry), placex.admin_level, placex.rank_address, placex.rank_search, placex.parent_place_id, parent.osm_type, parent.osm_id, placex.indexed_status, placex.linked_place_id from placex left outer join placex as parent on (placex.parent_place_id = parent.place_id) where placex.place_id = $1",
+ 1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- fprintf(stderr, "Error preparing placex_details: %s", PQerrorMessage(conn));
- exit(EXIT_FAILURE);
- }
+ {
+ fprintf(stderr, "Error preparing placex_details: %s", PQerrorMessage(conn));
+ exit(EXIT_FAILURE);
+ }
PQclear(res);
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(conn, "placex_address",
- "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",
- 1, pg_prepare_params);
+ "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",
+ 1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- fprintf(stderr, "Error preparing placex_address: %s", PQerrorMessage(conn));
- exit(EXIT_FAILURE);
- }
+ {
+ fprintf(stderr, "Error preparing placex_address: %s", PQerrorMessage(conn));
+ exit(EXIT_FAILURE);
+ }
PQclear(res);
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(conn, "placex_names",
- "select (each(name)).key,(each(name)).value from (select name as name from placex where place_id = $1) as x",
- 1, pg_prepare_params);
+ "select (each(name)).key,(each(name)).value from (select name from placex where place_id = $1) as x order by (each(name)).key",
+ 1, pg_prepare_params);
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "Error preparing placex_names: %s", PQerrorMessage(conn));
+ exit(EXIT_FAILURE);
+ }
+ PQclear(res);
+
+ pg_prepare_params[0] = PG_OID_INT8;
+ res = PQprepare(conn, "placex_extratags",
+ "select (each(extratags)).key,(each(extratags)).value from (select extratags from placex where place_id = $1) as x order by (each(extratags)).key",
+ 1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- fprintf(stderr, "Error preparing placex_names: %s", PQerrorMessage(conn));
- exit(EXIT_FAILURE);
- }
+ {
+ fprintf(stderr, "Error preparing placex_extratags: %s", PQerrorMessage(conn));
+ exit(EXIT_FAILURE);
+ }
PQclear(res);
}
xmlTextWriterPtr writer;
writer = xmlNewTextWriterFilename(structuredoutputfile, 0);
- if (writer==NULL)
- {
- fprintf(stderr, "Unable to open %s\n", structuredoutputfile);
- exit(EXIT_FAILURE);
- }
- xmlTextWriterSetIndent(writer, 1);
+ if (writer==NULL)
+ {
+ fprintf(stderr, "Unable to open %s\n", structuredoutputfile);
+ exit(EXIT_FAILURE);
+ }
+ xmlTextWriterSetIndent(writer, 1);
if (xmlTextWriterStartDocument(writer, NULL, "UTF8", NULL) < 0)
{
- fprintf(stderr, "xmlTextWriterStartDocument failed\n");
- exit(EXIT_FAILURE);
+ fprintf(stderr, "xmlTextWriterStartDocument failed\n");
+ exit(EXIT_FAILURE);
}
if (xmlTextWriterStartElement(writer, BAD_CAST "osmStructured") < 0)
{
- fprintf(stderr, "xmlTextWriterStartElement failed\n");
- exit(EXIT_FAILURE);
+ fprintf(stderr, "xmlTextWriterStartElement failed\n");
+ exit(EXIT_FAILURE);
}
if (xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "0.1") < 0)
{
- fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
- exit(EXIT_FAILURE);
+ fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
+ exit(EXIT_FAILURE);
}
if (xmlTextWriterWriteAttribute(writer, BAD_CAST "generator", BAD_CAST "Nominatim") < 0)
{
- fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
- exit(EXIT_FAILURE);
- }
- if (xmlTextWriterStartElement(writer, BAD_CAST "add") < 0)
- {
- fprintf(stderr, "xmlTextWriterStartElement failed\n");
- exit(EXIT_FAILURE);
+ fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
+ exit(EXIT_FAILURE);
}
+ mode = 0;
+
return writer;
}
void nominatim_exportXMLEnd(xmlTextWriterPtr writer)
{
- // End <add>
- if (xmlTextWriterEndElement(writer) < 0)
- {
- fprintf(stderr, "xmlTextWriterEndElement failed\n");
- exit(EXIT_FAILURE);
- }
- // End <osmStructured>
+ nominatim_exportEndMode(writer);
+
+ // End <osmStructured>
if (xmlTextWriterEndElement(writer) < 0)
{
- fprintf(stderr, "xmlTextWriterEndElement failed\n");
- exit(EXIT_FAILURE);
+ fprintf(stderr, "xmlTextWriterEndElement failed\n");
+ exit(EXIT_FAILURE);
}
if (xmlTextWriterEndDocument(writer) < 0)
{
- fprintf(stderr, "xmlTextWriterEndDocument failed\n");
- exit(EXIT_FAILURE);
+ fprintf(stderr, "xmlTextWriterEndDocument failed\n");
+ exit(EXIT_FAILURE);
}
xmlFreeTextWriter(writer);
}
-/*
- * Requirements: the prepared queries must exist
- */
-void nominatim_exportPlace(uint64_t place_id, PGconn * conn, xmlTextWriterPtr writer, pthread_mutex_t * writer_mutex)
+void nominatim_exportStartMode(xmlTextWriterPtr writer, int newMode)
+{
+ if (mode == newMode) return;
+
+ nominatim_exportEndMode(writer);
+
+ switch(newMode)
+ {
+ case 0:
+ break;
+
+ case 1:
+ if (xmlTextWriterStartElement(writer, BAD_CAST "add") < 0)
+ {
+ fprintf(stderr, "xmlTextWriterStartElement failed\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case 2:
+ if (xmlTextWriterStartElement(writer, BAD_CAST "update") < 0)
+ {
+ fprintf(stderr, "xmlTextWriterStartElement failed\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case 3:
+ if (xmlTextWriterStartElement(writer, BAD_CAST "delete") < 0)
+ {
+ fprintf(stderr, "xmlTextWriterStartElement failed\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+ mode = newMode;
+}
+
+void nominatim_exportEndMode(xmlTextWriterPtr writer)
{
- PGresult * res;
- PGresult * resNames;
- PGresult * resAddress;
+ if (!mode) return;
- int i;
+ if (xmlTextWriterEndElement(writer) < 0)
+ {
+ fprintf(stderr, "xmlTextWriterEndElement failed\n");
+ exit(EXIT_FAILURE);
+ }
+}
+void nominatim_exportPlaceQueries(uint64_t place_id, PGconn * conn, struct export_data * querySet)
+{
const char * paramValues[1];
int paramLengths[1];
int paramFormats[1];
uint64_t paramPlaceID;
-
- paramPlaceID = PGint64(place_id);
+ paramPlaceID = PGint64(place_id);
paramValues[0] = (char *)¶mPlaceID;
paramLengths[0] = sizeof(paramPlaceID);
paramFormats[0] = 1;
- res = PQexecPrepared(conn, "placex_details", 1, paramValues, paramLengths, paramFormats, 0);
- if (PQresultStatus(res) != PGRES_TUPLES_OK)
- {
- fprintf(stderr, "placex_details: SELECT failed: %s", PQerrorMessage(conn));
- PQclear(res);
- exit(EXIT_FAILURE);
- }
-
- resNames = PQexecPrepared(conn, "placex_names", 1, paramValues, paramLengths, paramFormats, 0);
- if (PQresultStatus(resNames) != PGRES_TUPLES_OK)
- {
- fprintf(stderr, "placex_names: SELECT failed: %s", PQerrorMessage(conn));
- PQclear(resNames);
- exit(EXIT_FAILURE);
- }
-
- resAddress = PQexecPrepared(conn, "placex_address", 1, paramValues, paramLengths, paramFormats, 0);
- if (PQresultStatus(resAddress) != PGRES_TUPLES_OK)
- {
- fprintf(stderr, "placex_address: SELECT failed: %s", PQerrorMessage(conn));
- PQclear(resAddress);
- exit(EXIT_FAILURE);
- }
-
- if (writer_mutex) pthread_mutex_lock( writer_mutex );
-
- xmlTextWriterStartElement(writer, BAD_CAST "feature");
- xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "place_id", "%li", place_id);
- xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(res, 0, 0));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(res, 0, 1));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(res, 0, 2));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(res, 0, 3));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(res, 0, 9));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "importance", BAD_CAST PQgetvalue(res, 0, 10));
-
- if (PQgetvalue(res, 0, 4) && strlen(PQgetvalue(res, 0, 4)))
- {
- xmlTextWriterStartElement(writer, BAD_CAST "names");
-
- for(i = 0; i < PQntuples(resNames); i++)
- {
- xmlTextWriterStartElement(writer, BAD_CAST "name");
- xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resNames, i, 0));
- xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(resNames, i, 1));
- xmlTextWriterEndElement(writer);
- }
-
- xmlTextWriterEndElement(writer);
- }
-
- if (PQgetvalue(res, 0, 5) && strlen(PQgetvalue(res, 0, 5)))
- {
- xmlTextWriterStartElement(writer, BAD_CAST "houseNumber");
- xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 5));
- xmlTextWriterEndElement(writer);
- }
-
- if (PQgetvalue(res, 0, 8) && strlen(PQgetvalue(res, 0, 8)))
- {
- xmlTextWriterStartElement(writer, BAD_CAST "adminLevel");
- xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 8));
- xmlTextWriterEndElement(writer);
- }
-
- if (PQgetvalue(res, 0, 6) && strlen(PQgetvalue(res, 0, 6)))
- {
- xmlTextWriterStartElement(writer, BAD_CAST "countryCode");
- xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 6));
- xmlTextWriterEndElement(writer);
- }
-
- if (PQntuples(resAddress)> 0)
- {
- xmlTextWriterStartElement(writer, BAD_CAST "address");
- for(i = 0; i < PQntuples(resAddress); i++)
- {
- xmlTextWriterStartElement(writer, BAD_CAST getRankLabel(atoi(PQgetvalue(resAddress, i, 5))));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(resAddress, i, 5));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resAddress, i, 0));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(resAddress, i, 1));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(resAddress, i, 2));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(resAddress, i, 3));
- xmlTextWriterWriteAttribute(writer, BAD_CAST "distance", BAD_CAST PQgetvalue(resAddress, i, 4));
- xmlTextWriterEndElement(writer);
- }
- xmlTextWriterEndElement(writer);
- }
-
- xmlTextWriterStartElement(writer, BAD_CAST "osmGeometry");
- xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 7));
- xmlTextWriterEndElement(writer);
-
- xmlTextWriterEndElement(writer); // </feature>
-
- if (writer_mutex) pthread_mutex_unlock( writer_mutex );
-
- PQclear(res);
- PQclear(resNames);
- PQclear(resAddress);
+ querySet->res = PQexecPrepared(conn, "placex_details", 1, paramValues, paramLengths, paramFormats, 0);
+ if (PQresultStatus(querySet->res) != PGRES_TUPLES_OK)
+ {
+ fprintf(stderr, "placex_details: SELECT failed: %s", PQerrorMessage(conn));
+ PQclear(querySet->res);
+ exit(EXIT_FAILURE);
+ }
+
+ querySet->resNames = PQexecPrepared(conn, "placex_names", 1, paramValues, paramLengths, paramFormats, 0);
+ if (PQresultStatus(querySet->resNames) != PGRES_TUPLES_OK)
+ {
+ fprintf(stderr, "placex_names: SELECT failed: %s", PQerrorMessage(conn));
+ PQclear(querySet->resNames);
+ exit(EXIT_FAILURE);
+ }
+
+ querySet->resAddress = PQexecPrepared(conn, "placex_address", 1, paramValues, paramLengths, paramFormats, 0);
+ if (PQresultStatus(querySet->resAddress) != PGRES_TUPLES_OK)
+ {
+ fprintf(stderr, "placex_address: SELECT failed: %s", PQerrorMessage(conn));
+ PQclear(querySet->resAddress);
+ exit(EXIT_FAILURE);
+ }
+
+ querySet->resExtraTags = PQexecPrepared(conn, "placex_extratags", 1, paramValues, paramLengths, paramFormats, 0);
+ if (PQresultStatus(querySet->resExtraTags) != PGRES_TUPLES_OK)
+ {
+ fprintf(stderr, "placex_extratags: SELECT failed: %s", PQerrorMessage(conn));
+ PQclear(querySet->resExtraTags);
+ exit(EXIT_FAILURE);
+ }
+}
+
+void nominatim_exportFreeQueries(struct export_data * querySet)
+{
+ PQclear(querySet->res);
+ PQclear(querySet->resNames);
+ PQclear(querySet->resAddress);
+ PQclear(querySet->resExtraTags);
+}
+
+/*
+ * Requirements: the prepared queries must exist
+ */
+void nominatim_exportPlace(uint64_t place_id, PGconn * conn,
+ xmlTextWriterPtr writer, pthread_mutex_t * writer_mutex, struct export_data * prevQuerySet)
+{
+ struct export_data querySet;
+
+ int i;
+
+ nominatim_exportPlaceQueries(place_id, conn, &querySet);
+
+ // Add, modify or delete?
+ if (prevQuerySet)
+ {
+ if ((PQgetvalue(prevQuerySet->res, 0, 14) && strcmp(PQgetvalue(prevQuerySet->res, 0, 14), "100") == 0) || PQntuples(querySet.res) == 0)
+ {
+ // Delete
+ if (writer_mutex) pthread_mutex_lock( writer_mutex );
+ nominatim_exportStartMode(writer, 3);
+ xmlTextWriterStartElement(writer, BAD_CAST "feature");
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "place_id", "%li", place_id);
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(prevQuerySet->res, 0, 0));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(prevQuerySet->res, 0, 1));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(prevQuerySet->res, 0, 2));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(prevQuerySet->res, 0, 3));
+ xmlTextWriterEndElement(writer);
+ if (writer_mutex) pthread_mutex_unlock( writer_mutex );
+ nominatim_exportFreeQueries(&querySet);
+ return;
+ }
+ if (PQgetvalue(prevQuerySet->res, 0, 14) && strcmp(PQgetvalue(prevQuerySet->res, 0, 14), "1") == 0)
+ {
+ // Add
+ if (writer_mutex) pthread_mutex_lock( writer_mutex );
+ nominatim_exportStartMode(writer, 1);
+ }
+ else
+ {
+ // Update, but only if something has changed
+
+ // TODO: detect changes
+
+ if (writer_mutex) pthread_mutex_lock( writer_mutex );
+ nominatim_exportStartMode(writer, 2);
+ }
+ }
+ else
+ {
+ // Add
+ if (writer_mutex) pthread_mutex_lock( writer_mutex );
+ nominatim_exportStartMode(writer, 1);
+ }
+
+ xmlTextWriterStartElement(writer, BAD_CAST "feature");
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "place_id", "%li", place_id);
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(querySet.res, 0, 0));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(querySet.res, 0, 1));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(querySet.res, 0, 2));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(querySet.res, 0, 3));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(querySet.res, 0, 9));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "importance", BAD_CAST PQgetvalue(querySet.res, 0, 10));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "parent_place_id", BAD_CAST PQgetvalue(querySet.res, 0, 11));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "parent_type", BAD_CAST PQgetvalue(querySet.res, 0, 12));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "parent_id", BAD_CAST PQgetvalue(querySet.res, 0, 13));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "linked_place_id", BAD_CAST PQgetvalue(querySet.res, 0, 15));
+
+ if (PQntuples(querySet.resNames))
+ {
+ xmlTextWriterStartElement(writer, BAD_CAST "names");
+
+ for (i = 0; i < PQntuples(querySet.resNames); i++)
+ {
+ xmlTextWriterStartElement(writer, BAD_CAST "name");
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(querySet.resNames, i, 0));
+ xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(querySet.resNames, i, 1));
+ xmlTextWriterEndElement(writer);
+ }
+
+ xmlTextWriterEndElement(writer);
+ }
+
+ if (PQgetvalue(querySet.res, 0, 5) && strlen(PQgetvalue(querySet.res, 0, 5)))
+ {
+ xmlTextWriterStartElement(writer, BAD_CAST "houseNumber");
+ xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(querySet.res, 0, 5));
+ xmlTextWriterEndElement(writer);
+ }
+
+ if (PQgetvalue(querySet.res, 0, 8) && strlen(PQgetvalue(querySet.res, 0, 8)))
+ {
+ xmlTextWriterStartElement(writer, BAD_CAST "adminLevel");
+ xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(querySet.res, 0, 8));
+ xmlTextWriterEndElement(writer);
+ }
+
+ if (PQgetvalue(querySet.res, 0, 6) && strlen(PQgetvalue(querySet.res, 0, 6)))
+ {
+ xmlTextWriterStartElement(writer, BAD_CAST "countryCode");
+ xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(querySet.res, 0, 6));
+ xmlTextWriterEndElement(writer);
+ }
+
+ if (PQntuples(querySet.resAddress) > 0)
+ {
+ xmlTextWriterStartElement(writer, BAD_CAST "address");
+ for (i = 0; i < PQntuples(querySet.resAddress); i++)
+ {
+ xmlTextWriterStartElement(writer, BAD_CAST getRankLabel(atoi(PQgetvalue(querySet.resAddress, i, 5))));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(querySet.resAddress, i, 5));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(querySet.resAddress, i, 0));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(querySet.resAddress, i, 1));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(querySet.resAddress, i, 2));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(querySet.resAddress, i, 3));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "distance", BAD_CAST PQgetvalue(querySet.resAddress, i, 4));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "isaddress", BAD_CAST PQgetvalue(querySet.resAddress, i, 6));
+ xmlTextWriterEndElement(writer);
+ }
+ xmlTextWriterEndElement(writer);
+ }
+
+ if (PQntuples(querySet.resExtraTags))
+ {
+ xmlTextWriterStartElement(writer, BAD_CAST "tags");
+
+ for (i = 0; i < PQntuples(querySet.resExtraTags); i++)
+ {
+ xmlTextWriterStartElement(writer, BAD_CAST "tag");
+ xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(querySet.resExtraTags, i, 0));
+ xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(querySet.resExtraTags, i, 1));
+ xmlTextWriterEndElement(writer);
+ }
+
+ xmlTextWriterEndElement(writer);
+ }
+
+
+ xmlTextWriterStartElement(writer, BAD_CAST "osmGeometry");
+ xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(querySet.res, 0, 7));
+ xmlTextWriterEndElement(writer);
+
+ xmlTextWriterEndElement(writer); // </feature>
+
+ if (writer_mutex) pthread_mutex_unlock( writer_mutex );
+
+ nominatim_exportFreeQueries(&querySet);
}
const char * getRankLabel(int rank)
{
- switch(rank)
- {
- case 0:
- case 1:
- return "continent";
- case 2:
- case 3:
- return "sea";
- case 4:
- case 5:
- case 6:
- case 7:
- return "country";
- case 8:
- case 9:
- case 10:
- case 11:
- return "state";
- case 12:
- case 13:
- case 14:
- case 15:
- return "county";
- case 16:
- return "city";
- case 17:
- return "town";
- case 18:
- return "village";
- case 19:
- return "unknown";
- case 20:
- return "suburb";
- case 21:
- return "postcode";
- case 22:
- return "neighborhood";
- case 23:
- return "postcode";
- case 24:
- return "unknown";
- case 25:
- return "postcode";
- case 26:
- return "street";
- case 27:
- return "access";
- case 28:
- return "building";
- case 29:
- default:
- return "other";
- }
+ switch (rank)
+ {
+ case 0:
+ case 1:
+ return "continent";
+ case 2:
+ case 3:
+ return "sea";
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return "country";
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ return "state";
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ return "county";
+ case 16:
+ return "city";
+ case 17:
+ return "town";
+ case 18:
+ return "village";
+ case 19:
+ return "unknown";
+ case 20:
+ return "suburb";
+ case 21:
+ return "postcode";
+ case 22:
+ return "neighborhood";
+ case 23:
+ return "postcode";
+ case 24:
+ return "unknown";
+ case 25:
+ return "postcode";
+ case 26:
+ return "street";
+ case 27:
+ return "access";
+ case 28:
+ return "building";
+ case 29:
+ default:
+ return "other";
+ }
}