2010-10-24 03:12:37 +04:00
/*
*/
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
# include <time.h>
# include <stdint.h>
# include <pthread.h>
# include <libpq-fe.h>
# include "nominatim.h"
# include "export.h"
# include "postgresql.h"
extern int verbose ;
2011-02-07 14:13:18 +03:00
int mode = 0 ;
2010-10-24 03:12:37 +04:00
void nominatim_export ( int rank_min , int rank_max , const char * conninfo , const char * structuredoutputfile )
{
xmlTextWriterPtr writer ;
2010-12-10 19:13:07 +03:00
int rankTotalDone ;
2010-10-24 03:12:37 +04:00
2010-12-10 19:13:07 +03:00
PGconn * conn ;
PGresult * res ;
PGresult * resSectors ;
PGresult * resPlaces ;
2010-10-24 03:12:37 +04:00
2010-12-10 19:13:07 +03:00
int rank ;
int i ;
int iSector ;
2010-10-24 03:12:37 +04:00
int tuples ;
const char * paramValues [ 2 ] ;
int paramLengths [ 2 ] ;
int paramFormats [ 2 ] ;
uint32_t paramRank ;
uint32_t paramSector ;
uint32_t sector ;
Oid pg_prepare_params [ 2 ] ;
2010-12-10 19:13:07 +03:00
conn = PQconnectdb ( conninfo ) ;
if ( PQstatus ( conn ) ! = CONNECTION_OK )
{
2010-10-24 03:12:37 +04:00
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 " ,
2010-12-10 19:13:07 +03:00
" 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 ) ;
2010-10-24 03:12:37 +04:00
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 " ,
2010-12-10 19:13:07 +03:00
" select place_id from placex where rank_search = $1 and geometry_sector = $2 " ,
2 , pg_prepare_params ) ;
2010-10-24 03:12:37 +04:00
if ( PQresultStatus ( res ) ! = PGRES_COMMAND_OK ) exit ( EXIT_FAILURE ) ;
PQclear ( res ) ;
nominatim_exportCreatePreparedQueries ( conn ) ;
2010-12-10 19:13:07 +03:00
// Create the output file
writer = nominatim_exportXMLStart ( structuredoutputfile ) ;
2010-10-24 03:12:37 +04:00
for ( rank = rank_min ; rank < = rank_max ; rank + + )
{
2010-12-10 19:13:07 +03:00
printf ( " Starting rank %d \n " , rank ) ;
2010-10-24 03:12:37 +04:00
paramRank = PGint32 ( rank ) ;
paramValues [ 0 ] = ( char * ) & paramRank ;
paramLengths [ 0 ] = sizeof ( paramRank ) ;
paramFormats [ 0 ] = 1 ;
resSectors = PQexecPrepared ( conn , " index_sectors " , 1 , paramValues , paramLengths , paramFormats , 1 ) ;
if ( PQresultStatus ( resSectors ) ! = PGRES_TUPLES_OK )
{
fprintf ( stderr , " index_sectors: SELECT failed: %s " , PQerrorMessage ( conn ) ) ;
PQclear ( resSectors ) ;
exit ( EXIT_FAILURE ) ;
}
2010-12-10 19:13:07 +03:00
if ( PQftype ( resSectors , 0 ) ! = PG_OID_INT4 )
{
2010-10-24 03:12:37 +04:00
fprintf ( stderr , " Sector value has unexpected type \n " ) ;
PQclear ( resSectors ) ;
exit ( EXIT_FAILURE ) ;
2010-12-10 19:13:07 +03:00
}
if ( PQftype ( resSectors , 1 ) ! = PG_OID_INT8 )
{
2010-10-24 03:12:37 +04:00
fprintf ( stderr , " Sector value has unexpected type \n " ) ;
PQclear ( resSectors ) ;
exit ( EXIT_FAILURE ) ;
2010-12-10 19:13:07 +03:00
}
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 * ) & paramRank ;
paramLengths [ 0 ] = sizeof ( paramRank ) ;
paramFormats [ 0 ] = 1 ;
paramSector = PGint32 ( sector ) ;
paramValues [ 1 ] = ( char * ) & paramSector ;
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_INT4 )
{
fprintf ( stderr , " Place_id value has unexpected type \n " ) ;
PQclear ( resPlaces ) ;
exit ( EXIT_FAILURE ) ;
}
tuples = PQntuples ( resPlaces ) ;
for ( i = 0 ; i < tuples ; i + + )
{
2011-02-07 14:13:18 +03:00
nominatim_exportPlace ( PGint32 ( * ( ( uint32_t * ) PQgetvalue ( resPlaces , i , 0 ) ) ) , conn , writer , NULL , NULL ) ;
2010-12-10 19:13:07 +03:00
rankTotalDone + + ;
if ( rankTotalDone % 1000 = = 0 ) printf ( " Done %i (k) \n " , rankTotalDone / 1000 ) ;
}
2010-10-24 03:12:37 +04:00
PQclear ( resPlaces ) ;
2010-12-10 19:13:07 +03:00
}
2010-10-24 03:12:37 +04:00
PQclear ( resSectors ) ;
}
nominatim_exportXMLEnd ( writer ) ;
PQfinish ( conn ) ;
}
void nominatim_exportCreatePreparedQueries ( PGconn * conn )
{
Oid pg_prepare_params [ 2 ] ;
2010-12-10 19:13:07 +03:00
PGresult * res ;
2010-10-24 03:12:37 +04:00
pg_prepare_params [ 0 ] = PG_OID_INT8 ;
res = PQprepare ( conn , " placex_details " ,
2011-02-07 14:13:18 +03:00
" 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 from placex left outer join placex as parent on (placex.parent_place_id = parent.place_id) where placex.place_id = $1 " ,
2010-12-10 19:13:07 +03:00
1 , pg_prepare_params ) ;
2010-10-26 19:22:41 +04:00
if ( PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
2010-12-10 19:13:07 +03:00
{
fprintf ( stderr , " Error preparing placex_details: %s " , PQerrorMessage ( conn ) ) ;
exit ( EXIT_FAILURE ) ;
}
2010-10-24 03:12:37 +04:00
PQclear ( res ) ;
pg_prepare_params [ 0 ] = PG_OID_INT8 ;
res = PQprepare ( conn , " placex_address " ,
2011-01-21 13:40:44 +03:00
" 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 " ,
2010-12-10 19:13:07 +03:00
1 , pg_prepare_params ) ;
2010-10-26 19:22:41 +04:00
if ( PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
2010-12-10 19:13:07 +03:00
{
fprintf ( stderr , " Error preparing placex_address: %s " , PQerrorMessage ( conn ) ) ;
exit ( EXIT_FAILURE ) ;
}
2010-10-24 03:12:37 +04:00
PQclear ( res ) ;
pg_prepare_params [ 0 ] = PG_OID_INT8 ;
res = PQprepare ( conn , " placex_names " ,
2011-01-21 13:40:44 +03:00
" select (each(name)).key,(each(name)).value from (select name from placex where place_id = $1) as x order by (each(name)).key " ,
2010-12-10 19:13:07 +03:00
1 , pg_prepare_params ) ;
2010-10-26 19:22:41 +04:00
if ( PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
2010-12-10 19:13:07 +03:00
{
fprintf ( stderr , " Error preparing placex_names: %s " , PQerrorMessage ( conn ) ) ;
exit ( EXIT_FAILURE ) ;
}
2010-10-24 03:12:37 +04:00
PQclear ( res ) ;
2010-12-07 16:41:02 +03:00
pg_prepare_params [ 0 ] = PG_OID_INT8 ;
res = PQprepare ( conn , " placex_extratags " ,
2011-01-21 13:40:44 +03:00
" select (each(extratags)).key,(each(extratags)).value from (select extratags from placex where place_id = $1) as x order by (each(extratags)).key " ,
2010-12-10 19:13:07 +03:00
1 , pg_prepare_params ) ;
2010-12-07 16:41:02 +03:00
if ( PQresultStatus ( res ) ! = PGRES_COMMAND_OK )
2010-12-10 19:13:07 +03:00
{
fprintf ( stderr , " Error preparing placex_extratags: %s " , PQerrorMessage ( conn ) ) ;
exit ( EXIT_FAILURE ) ;
}
2010-12-07 16:41:02 +03:00
PQclear ( res ) ;
2010-10-24 03:12:37 +04:00
}
xmlTextWriterPtr nominatim_exportXMLStart ( const char * structuredoutputfile )
{
xmlTextWriterPtr writer ;
writer = xmlNewTextWriterFilename ( structuredoutputfile , 0 ) ;
2010-12-10 19:13:07 +03:00
if ( writer = = NULL )
{
fprintf ( stderr , " Unable to open %s \n " , structuredoutputfile ) ;
exit ( EXIT_FAILURE ) ;
}
xmlTextWriterSetIndent ( writer , 1 ) ;
2010-10-24 03:12:37 +04:00
if ( xmlTextWriterStartDocument ( writer , NULL , " UTF8 " , NULL ) < 0 )
{
2010-12-10 19:13:07 +03:00
fprintf ( stderr , " xmlTextWriterStartDocument failed \n " ) ;
exit ( EXIT_FAILURE ) ;
2010-10-24 03:12:37 +04:00
}
if ( xmlTextWriterStartElement ( writer , BAD_CAST " osmStructured " ) < 0 )
{
2010-12-10 19:13:07 +03:00
fprintf ( stderr , " xmlTextWriterStartElement failed \n " ) ;
exit ( EXIT_FAILURE ) ;
2010-10-24 03:12:37 +04:00
}
if ( xmlTextWriterWriteAttribute ( writer , BAD_CAST " version " , BAD_CAST " 0.1 " ) < 0 )
{
2010-12-10 19:13:07 +03:00
fprintf ( stderr , " xmlTextWriterWriteAttribute failed \n " ) ;
exit ( EXIT_FAILURE ) ;
2010-10-24 03:12:37 +04:00
}
if ( xmlTextWriterWriteAttribute ( writer , BAD_CAST " generator " , BAD_CAST " Nominatim " ) < 0 )
{
2010-12-10 19:13:07 +03:00
fprintf ( stderr , " xmlTextWriterWriteAttribute failed \n " ) ;
exit ( EXIT_FAILURE ) ;
2010-10-24 03:12:37 +04:00
}
2011-02-07 14:13:18 +03:00
mode = 0 ;
2010-10-24 03:12:37 +04:00
return writer ;
}
void nominatim_exportXMLEnd ( xmlTextWriterPtr writer )
{
2011-02-07 14:13:18 +03:00
nominatim_exportEndMode ( writer ) ;
2010-12-10 19:13:07 +03:00
// End <osmStructured>
2010-10-24 03:12:37 +04:00
if ( xmlTextWriterEndElement ( writer ) < 0 )
{
2010-12-10 19:13:07 +03:00
fprintf ( stderr , " xmlTextWriterEndElement failed \n " ) ;
exit ( EXIT_FAILURE ) ;
2010-10-24 03:12:37 +04:00
}
if ( xmlTextWriterEndDocument ( writer ) < 0 )
{
2010-12-10 19:13:07 +03:00
fprintf ( stderr , " xmlTextWriterEndDocument failed \n " ) ;
exit ( EXIT_FAILURE ) ;
2010-10-24 03:12:37 +04:00
}
xmlFreeTextWriter ( writer ) ;
}
2011-02-07 14:13:18 +03:00
void nominatim_exportStartMode ( xmlTextWriterPtr writer , int newMode )
2010-10-24 03:12:37 +04:00
{
2011-02-07 14:13:18 +03:00
if ( mode = = newMode ) return ;
2010-10-24 03:12:37 +04:00
2011-02-07 14:13:18 +03:00
nominatim_exportEndMode ( writer ) ;
switch ( newMode )
{
case 0 :
break ;
2010-10-24 03:12:37 +04:00
2011-02-07 14:13:18 +03:00
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 )
{
if ( ! mode ) return ;
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 )
{
2010-10-24 03:12:37 +04:00
const char * paramValues [ 1 ] ;
int paramLengths [ 1 ] ;
int paramFormats [ 1 ] ;
uint64_t paramPlaceID ;
2010-12-10 19:13:07 +03:00
paramPlaceID = PGint64 ( place_id ) ;
2010-10-24 03:12:37 +04:00
paramValues [ 0 ] = ( char * ) & paramPlaceID ;
paramLengths [ 0 ] = sizeof ( paramPlaceID ) ;
paramFormats [ 0 ] = 1 ;
2011-02-07 14:13:18 +03:00
querySet - > res = PQexecPrepared ( conn , " placex_details " , 1 , paramValues , paramLengths , paramFormats , 0 ) ;
if ( PQresultStatus ( querySet - > res ) ! = PGRES_TUPLES_OK )
2010-12-10 19:13:07 +03:00
{
fprintf ( stderr , " placex_details: SELECT failed: %s " , PQerrorMessage ( conn ) ) ;
2011-02-07 14:13:18 +03:00
PQclear ( querySet - > res ) ;
2010-12-10 19:13:07 +03:00
exit ( EXIT_FAILURE ) ;
}
2011-02-07 14:13:18 +03:00
querySet - > resNames = PQexecPrepared ( conn , " placex_names " , 1 , paramValues , paramLengths , paramFormats , 0 ) ;
if ( PQresultStatus ( querySet - > resNames ) ! = PGRES_TUPLES_OK )
2010-12-10 19:13:07 +03:00
{
fprintf ( stderr , " placex_names: SELECT failed: %s " , PQerrorMessage ( conn ) ) ;
2011-02-07 14:13:18 +03:00
PQclear ( querySet - > resNames ) ;
2010-12-10 19:13:07 +03:00
exit ( EXIT_FAILURE ) ;
}
2011-02-07 14:13:18 +03:00
querySet - > resAddress = PQexecPrepared ( conn , " placex_address " , 1 , paramValues , paramLengths , paramFormats , 0 ) ;
if ( PQresultStatus ( querySet - > resAddress ) ! = PGRES_TUPLES_OK )
2010-12-10 19:13:07 +03:00
{
fprintf ( stderr , " placex_address: SELECT failed: %s " , PQerrorMessage ( conn ) ) ;
2011-02-07 14:13:18 +03:00
PQclear ( querySet - > resAddress ) ;
2010-12-10 19:13:07 +03:00
exit ( EXIT_FAILURE ) ;
}
2011-02-07 14:13:18 +03:00
querySet - > resExtraTags = PQexecPrepared ( conn , " placex_extratags " , 1 , paramValues , paramLengths , paramFormats , 0 ) ;
if ( PQresultStatus ( querySet - > resExtraTags ) ! = PGRES_TUPLES_OK )
2010-12-10 19:13:07 +03:00
{
fprintf ( stderr , " placex_extratags: SELECT failed: %s " , PQerrorMessage ( conn ) ) ;
2011-02-07 14:13:18 +03:00
PQclear ( querySet - > resExtraTags ) ;
2010-12-10 19:13:07 +03:00
exit ( EXIT_FAILURE ) ;
}
2011-02-07 14:13:18 +03:00
}
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 ) )
{
// 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
2010-12-10 19:13:07 +03:00
2011-02-07 14:13:18 +03:00
// 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 ) ;
}
2010-12-10 19:13:07 +03:00
xmlTextWriterStartElement ( writer , BAD_CAST " feature " ) ;
xmlTextWriterWriteFormatAttribute ( writer , BAD_CAST " place_id " , " %li " , place_id ) ;
2011-02-07 14:13:18 +03:00
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 ) ) ;
if ( PQntuples ( querySet . resNames ) )
2010-12-10 19:13:07 +03:00
{
xmlTextWriterStartElement ( writer , BAD_CAST " names " ) ;
2011-02-07 14:13:18 +03:00
for ( i = 0 ; i < PQntuples ( querySet . resNames ) ; i + + )
2010-12-10 19:13:07 +03:00
{
xmlTextWriterStartElement ( writer , BAD_CAST " name " ) ;
2011-02-07 14:13:18 +03:00
xmlTextWriterWriteAttribute ( writer , BAD_CAST " type " , BAD_CAST PQgetvalue ( querySet . resNames , i , 0 ) ) ;
xmlTextWriterWriteString ( writer , BAD_CAST PQgetvalue ( querySet . resNames , i , 1 ) ) ;
2010-12-10 19:13:07 +03:00
xmlTextWriterEndElement ( writer ) ;
}
xmlTextWriterEndElement ( writer ) ;
}
2011-02-07 14:13:18 +03:00
if ( PQgetvalue ( querySet . res , 0 , 5 ) & & strlen ( PQgetvalue ( querySet . res , 0 , 5 ) ) )
2010-12-10 19:13:07 +03:00
{
xmlTextWriterStartElement ( writer , BAD_CAST " houseNumber " ) ;
2011-02-07 14:13:18 +03:00
xmlTextWriterWriteString ( writer , BAD_CAST PQgetvalue ( querySet . res , 0 , 5 ) ) ;
2010-12-10 19:13:07 +03:00
xmlTextWriterEndElement ( writer ) ;
}
2011-02-07 14:13:18 +03:00
if ( PQgetvalue ( querySet . res , 0 , 8 ) & & strlen ( PQgetvalue ( querySet . res , 0 , 8 ) ) )
2010-12-10 19:13:07 +03:00
{
xmlTextWriterStartElement ( writer , BAD_CAST " adminLevel " ) ;
2011-02-07 14:13:18 +03:00
xmlTextWriterWriteString ( writer , BAD_CAST PQgetvalue ( querySet . res , 0 , 8 ) ) ;
2010-12-10 19:13:07 +03:00
xmlTextWriterEndElement ( writer ) ;
}
2011-02-07 14:13:18 +03:00
if ( PQgetvalue ( querySet . res , 0 , 6 ) & & strlen ( PQgetvalue ( querySet . res , 0 , 6 ) ) )
2010-12-10 19:13:07 +03:00
{
xmlTextWriterStartElement ( writer , BAD_CAST " countryCode " ) ;
2011-02-07 14:13:18 +03:00
xmlTextWriterWriteString ( writer , BAD_CAST PQgetvalue ( querySet . res , 0 , 6 ) ) ;
2010-12-10 19:13:07 +03:00
xmlTextWriterEndElement ( writer ) ;
}
2011-02-07 14:13:18 +03:00
if ( PQntuples ( querySet . resAddress ) > 0 )
2010-12-10 19:13:07 +03:00
{
xmlTextWriterStartElement ( writer , BAD_CAST " address " ) ;
2011-02-07 14:13:18 +03:00
for ( i = 0 ; i < PQntuples ( querySet . resAddress ) ; i + + )
2010-12-10 19:13:07 +03:00
{
2011-02-07 14:13:18 +03:00
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 ) ) ;
2010-12-10 19:13:07 +03:00
xmlTextWriterEndElement ( writer ) ;
}
xmlTextWriterEndElement ( writer ) ;
}
2011-02-07 14:13:18 +03:00
if ( PQntuples ( querySet . resExtraTags ) )
2010-12-10 19:13:07 +03:00
{
xmlTextWriterStartElement ( writer , BAD_CAST " tags " ) ;
2011-02-07 14:13:18 +03:00
for ( i = 0 ; i < PQntuples ( querySet . resExtraTags ) ; i + + )
2010-12-10 19:13:07 +03:00
{
xmlTextWriterStartElement ( writer , BAD_CAST " tag " ) ;
2011-02-07 14:13:18 +03:00
xmlTextWriterWriteAttribute ( writer , BAD_CAST " type " , BAD_CAST PQgetvalue ( querySet . resExtraTags , i , 0 ) ) ;
xmlTextWriterWriteString ( writer , BAD_CAST PQgetvalue ( querySet . resExtraTags , i , 1 ) ) ;
2010-12-10 19:13:07 +03:00
xmlTextWriterEndElement ( writer ) ;
}
xmlTextWriterEndElement ( writer ) ;
}
xmlTextWriterStartElement ( writer , BAD_CAST " osmGeometry " ) ;
2011-02-07 14:13:18 +03:00
xmlTextWriterWriteString ( writer , BAD_CAST PQgetvalue ( querySet . res , 0 , 7 ) ) ;
2010-12-10 19:13:07 +03:00
xmlTextWriterEndElement ( writer ) ;
xmlTextWriterEndElement ( writer ) ; // </feature>
if ( writer_mutex ) pthread_mutex_unlock ( writer_mutex ) ;
2011-02-07 14:13:18 +03:00
nominatim_exportFreeQueries ( & querySet ) ;
2010-10-24 03:12:37 +04:00
}
const char * getRankLabel ( int rank )
{
2010-12-10 19:13:07 +03:00
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 " ;
}
2010-10-24 03:12:37 +04:00
}