]> git.openstreetmap.org Git - nominatim.git/blob - nominatim/import.c
finally fix adminitrative spelling error, disable fast_update on indexes by default...
[nominatim.git] / nominatim / import.c
1 /*
2 */
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include <libpq-fe.h>
7
8 #include <libxml/xmlstring.h>
9 #include <libxml/xmlreader.h>
10 #include <libxml/hash.h>
11
12 #include "nominatim.h"
13 #include "import.h"
14 #include "input.h"
15
16 typedef enum { FILETYPE_NONE, FILETYPE_STRUCTUREDV0P1 } filetypes_t;
17 typedef enum { FILEMODE_NONE, FILEMODE_ADD, FILEMODE_UPDATE, FILEMODE_DELETE } filemodes_t;
18
19 #define MAX_FEATUREADDRESS 500
20 #define MAX_FEATURENAMES 1000
21 #define MAX_FEATUREEXTRATAGS 100
22 #define MAX_FEATURENAMESTRING 100000
23 #define MAX_FEATUREEXTRATAGSTRING 50000
24
25 struct feature_address
26 {
27     int                 place_id;
28     int                 rankAddress;
29     char                        isAddress[2];
30     xmlChar *   type;
31     xmlChar *   id;
32     xmlChar *   key;
33     xmlChar *   value;
34     xmlChar *   distance;
35 };
36
37 struct feature_tag
38 {
39     xmlChar *   type;
40     xmlChar *   value;
41 };
42
43 struct feature
44 {
45     int                 placeID;
46     xmlChar *   type;
47     xmlChar *   id;
48     xmlChar *   key;
49     xmlChar *   value;
50     xmlChar *   rankAddress;
51     xmlChar *   rankSearch;
52     xmlChar *   countryCode;
53     xmlChar *   adminLevel;
54     xmlChar *   houseNumber;
55     xmlChar *   geometry;
56 } feature;
57
58 int                                     fileType = FILETYPE_NONE;
59 int                                     fileMode = FILEMODE_ADD;
60 PGconn *                                conn;
61 struct feature_address  featureAddress[MAX_FEATUREADDRESS];
62 struct feature_tag              featureName[MAX_FEATURENAMES];
63 struct feature_tag              featureExtraTag[MAX_FEATUREEXTRATAGS];
64 struct feature                  feature;
65 int                                     featureAddressLines = 0;
66 int                                     featureNameLines = 0;
67 int                                     featureExtraTagLines = 0;
68 int                                     featureCount = 0;
69 xmlHashTablePtr                 partionTableTagsHash;
70 char                                    featureNameString[MAX_FEATURENAMESTRING];
71 char                                    featureExtraTagString[MAX_FEATUREEXTRATAGSTRING];
72
73 void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
74 {
75     char * value;
76     float version;
77     int isAddressLine;
78
79     if (fileType == FILETYPE_NONE)
80     {
81         // Potential to handle other file types in the future / versions
82         if (xmlStrEqual(name, BAD_CAST "osmStructured"))
83         {
84             value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version");
85             version = strtof(value, NULL);
86             xmlFree(value);
87
88             if (version == (float)0.1)
89             {
90                 fileType = FILETYPE_STRUCTUREDV0P1;
91                 fileMode = FILEMODE_ADD;
92             }
93             else
94             {
95                 fprintf( stderr, "Unknown osmStructured version %f\n", version );
96                 exit_nicely();
97             }
98         }
99         else
100         {
101             fprintf( stderr, "Unknown XML document type: %s\n", name );
102             exit_nicely();
103         }
104         return;
105     }
106
107     if (xmlStrEqual(name, BAD_CAST "add"))
108     {
109         fileMode = FILEMODE_ADD;
110         return;
111     }
112     if (xmlStrEqual(name, BAD_CAST "update"))
113     {
114         fileMode = FILEMODE_UPDATE;
115         return;
116     }
117     if (xmlStrEqual(name, BAD_CAST "delete"))
118     {
119         fileMode = FILEMODE_DELETE;
120         return;
121     }
122     if (fileMode == FILEMODE_NONE)
123     {
124         fprintf( stderr, "Unknown import mode in: %s\n", name );
125         exit_nicely();
126     }
127
128     if (xmlStrEqual(name, BAD_CAST "feature"))
129     {
130         feature.type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
131         feature.id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
132         feature.key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
133         feature.value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
134         feature.rankAddress = xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
135         feature.rankSearch = xmlTextReaderGetAttribute(reader, BAD_CAST "importance");
136
137         feature.countryCode = NULL;
138         feature.adminLevel = NULL;
139         feature.houseNumber = NULL;
140         feature.geometry = NULL;
141         featureAddressLines = 0;
142         featureNameLines = 0;
143
144         return;
145     }
146     if (xmlStrEqual(name, BAD_CAST "names")) return;
147     if (xmlStrEqual(name, BAD_CAST "name"))
148     {
149         featureName[featureNameLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
150         featureName[featureNameLines].value = xmlTextReaderReadString(reader);
151         featureNameLines++;
152         if (featureNameLines >= MAX_FEATURENAMES)
153         {
154             fprintf( stderr, "Too many name elements\n");
155             exit_nicely();
156         }
157         return;
158     }
159     if (xmlStrEqual(name, BAD_CAST "tags")) return;
160     if (xmlStrEqual(name, BAD_CAST "tag"))
161     {
162         featureExtraTag[featureExtraTagLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
163         featureExtraTag[featureExtraTagLines].value = xmlTextReaderReadString(reader);
164         featureExtraTagLines++;
165         if (featureExtraTagLines >= MAX_FEATUREEXTRATAGS)
166         {
167             fprintf( stderr, "Too many extra tag elements\n");
168             exit_nicely();
169         }
170         return;
171     }
172     if (xmlStrEqual(name, BAD_CAST "osmGeometry"))
173     {
174         feature.geometry = xmlTextReaderReadString(reader);
175         return;
176     }
177     if (xmlStrEqual(name, BAD_CAST "adminLevel"))
178     {
179         feature.adminLevel = xmlTextReaderReadString(reader);
180         return;
181     }
182     if (xmlStrEqual(name, BAD_CAST "countryCode"))
183     {
184         feature.countryCode = xmlTextReaderReadString(reader);
185         return;
186     }
187     if (xmlStrEqual(name, BAD_CAST "houseNumber"))
188     {
189         feature.houseNumber = xmlTextReaderReadString(reader);
190         return;
191     }
192     if (xmlStrEqual(name, BAD_CAST "address"))
193     {
194         featureAddressLines = 0;
195         return;
196     }
197     isAddressLine = 0;
198     if (xmlStrEqual(name, BAD_CAST "continent"))
199     {
200         isAddressLine = 1;
201     }
202     else if (xmlStrEqual(name, BAD_CAST "sea"))
203     {
204         isAddressLine = 1;
205     }
206     else if (xmlStrEqual(name, BAD_CAST "country"))
207     {
208         isAddressLine = 1;
209     }
210     else if (xmlStrEqual(name, BAD_CAST "state"))
211     {
212         isAddressLine = 1;
213     }
214     else if (xmlStrEqual(name, BAD_CAST "county"))
215     {
216         isAddressLine = 1;
217     }
218     else if (xmlStrEqual(name, BAD_CAST "city"))
219     {
220         isAddressLine = 1;
221     }
222     else if (xmlStrEqual(name, BAD_CAST "town"))
223     {
224         isAddressLine = 1;
225     }
226     else if (xmlStrEqual(name, BAD_CAST "village"))
227     {
228         isAddressLine = 1;
229     }
230     else if (xmlStrEqual(name, BAD_CAST "unknown"))
231     {
232         isAddressLine = 1;
233     }
234     else if (xmlStrEqual(name, BAD_CAST "suburb"))
235     {
236         isAddressLine = 1;
237     }
238     else if (xmlStrEqual(name, BAD_CAST "postcode"))
239     {
240         isAddressLine = 1;
241     }
242     else if (xmlStrEqual(name, BAD_CAST "neighborhood"))
243     {
244         isAddressLine = 1;
245     }
246     else if (xmlStrEqual(name, BAD_CAST "street"))
247     {
248         isAddressLine = 1;
249     }
250     else if (xmlStrEqual(name, BAD_CAST "access"))
251     {
252         isAddressLine = 1;
253     }
254     else if (xmlStrEqual(name, BAD_CAST "building"))
255     {
256         isAddressLine = 1;
257     }
258     else if (xmlStrEqual(name, BAD_CAST "other"))
259     {
260         isAddressLine = 1;
261     }
262     if (isAddressLine)
263     {
264         value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
265         if (!value)
266         {
267             fprintf( stderr, "Address element missing rank\n");
268             exit_nicely();
269         }
270         featureAddress[featureAddressLines].rankAddress =  atoi(value);
271         xmlFree(value);
272
273         value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "isaddress");
274         if (!value)
275         {
276             fprintf( stderr, "Address element missing rank\n");
277             exit_nicely();
278         }
279         if (*value == 't') strcpy(featureAddress[featureAddressLines].isAddress, "t");
280         else strcpy(featureAddress[featureAddressLines].isAddress, "f");
281         xmlFree(value);
282
283         featureAddress[featureAddressLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
284         featureAddress[featureAddressLines].id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
285         featureAddress[featureAddressLines].key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
286         featureAddress[featureAddressLines].value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
287         featureAddress[featureAddressLines].distance = xmlTextReaderGetAttribute(reader, BAD_CAST "distance");
288
289         featureAddressLines++;
290         if (featureAddressLines >= MAX_FEATUREADDRESS)
291         {
292             fprintf( stderr, "Too many address elements\n");
293             exit_nicely();
294         }
295
296         return;
297     }
298     fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
299 }
300
301 void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
302 {
303     PGresult *          res;
304     PGresult *          resPlaceID;
305     const char *        paramValues[11];
306     char *                      place_id;
307     char *                      partionQueryName;
308     int i, namePos, lineTypeLen, lineValueLen;
309
310     if (xmlStrEqual(name, BAD_CAST "feature"))
311     {
312         featureCount++;
313         if (featureCount % 1000 == 0) printf("feature %i(k)\n", featureCount/1000);
314
315         if (fileMode == FILEMODE_ADD)
316         {
317             resPlaceID = PQexecPrepared(conn, "get_new_place_id", 0, NULL, NULL, NULL, 0);
318             if (PQresultStatus(resPlaceID) != PGRES_TUPLES_OK)
319             {
320                 fprintf(stderr, "get_place_id: INSERT failed: %s", PQerrorMessage(conn));
321                 PQclear(resPlaceID);
322                 exit(EXIT_FAILURE);
323             }
324         }
325         else
326         {
327             paramValues[0] = (const char *)feature.type;
328             paramValues[1] = (const char *)feature.id;
329             paramValues[2] = (const char *)feature.key;
330             paramValues[3] = (const char *)feature.value;
331             resPlaceID = PQexecPrepared(conn, "get_new_place_id", 4, paramValues, NULL, NULL, 0);
332             if (PQresultStatus(resPlaceID) != PGRES_TUPLES_OK)
333             {
334                 fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
335                 PQclear(resPlaceID);
336                 exit(EXIT_FAILURE);
337             }
338         }
339         place_id = PQgetvalue(resPlaceID, 0, 0);
340
341         if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_DELETE)
342         {
343             paramValues[0] = (const char *)place_id;
344             res = PQexecPrepared(conn, "placex_delete", 1, paramValues, NULL, NULL, 0);
345             if (PQresultStatus(res) != PGRES_COMMAND_OK)
346             {
347                 fprintf(stderr, "placex_delete: DELETE failed: %s", PQerrorMessage(conn));
348                 PQclear(res);
349                 exit(EXIT_FAILURE);
350             }
351             PQclear(res);
352
353             res = PQexecPrepared(conn, "search_name_delete", 1, paramValues, NULL, NULL, 0);
354             if (PQresultStatus(res) != PGRES_COMMAND_OK)
355             {
356                 fprintf(stderr, "search_name_delete: DELETE failed: %s", PQerrorMessage(conn));
357                 PQclear(res);
358                 exit(EXIT_FAILURE);
359             }
360             PQclear(res);
361
362             res = PQexecPrepared(conn, "place_addressline_delete", 1, paramValues, NULL, NULL, 0);
363             if (PQresultStatus(res) != PGRES_COMMAND_OK)
364             {
365                 fprintf(stderr, "place_addressline_delete: DELETE failed: %s", PQerrorMessage(conn));
366                 PQclear(res);
367                 exit(EXIT_FAILURE);
368             }
369             PQclear(res);
370         }
371
372         if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_ADD)
373         {
374             // Insert into placex
375             paramValues[0] = (const char *)place_id;
376             paramValues[1] = (const char *)feature.type;
377             paramValues[2] = (const char *)feature.id;
378             paramValues[3] = (const char *)feature.key;
379             paramValues[4] = (const char *)feature.value;
380
381             featureNameString[0] = 0;
382             if (featureNameLines)
383             {
384                 namePos = 0;
385                 lineTypeLen = 0;
386                 lineValueLen = 0;
387                 for (i = 0; i < featureNameLines; i++)
388                 {
389                     lineTypeLen = strlen(BAD_CAST featureName[i].type);
390                     lineValueLen = strlen(BAD_CAST featureName[i].value);
391                     if (namePos+lineTypeLen+lineValueLen+7 > MAX_FEATURENAMESTRING)
392                     {
393                         fprintf(stderr, "feature name too long: %s", (const char *)featureName[i].value);
394                         break;
395                     }
396                     if (namePos) strcpy(featureNameString+(namePos++), ",");
397                     strcpy(featureNameString+(namePos++), "\"");
398                     strcpy(featureNameString+namePos, BAD_CAST featureName[i].type);
399                     namePos += lineTypeLen;
400                     strcpy(featureNameString+namePos, "\"=>\"");
401                     namePos += 4;
402                     strcpy(featureNameString+namePos, BAD_CAST featureName[i].value);
403                     namePos += lineValueLen;
404                     strcpy(featureNameString+(namePos++), "\"");
405                 }
406             }
407             paramValues[5] = (const char *)featureNameString;
408
409             featureExtraTagString[0] = 0;
410             if (featureExtraTagLines)
411             {
412                 namePos = 0;
413                 lineTypeLen = 0;
414                 lineValueLen = 0;
415                 for (i = 0; i < featureExtraTagLines; i++)
416                 {
417                     lineTypeLen = strlen(BAD_CAST featureExtraTag[i].type);
418                     lineValueLen = strlen(BAD_CAST featureExtraTag[i].value);
419                     if (namePos+lineTypeLen+lineValueLen+7 > MAX_FEATUREEXTRATAGSTRING)
420                     {
421                         fprintf(stderr, "feature extra tag too long: %s", (const char *)featureExtraTag[i].value);
422                         break;
423                     }
424                     if (namePos) strcpy(featureExtraTagString+(namePos++),",");
425                     strcpy(featureExtraTagString+(namePos++), "\"");
426                     strcpy(featureExtraTagString+namePos, BAD_CAST featureExtraTag[i].type);
427                     namePos += lineTypeLen;
428                     strcpy(featureExtraTagString+namePos, "\"=>\"");
429                     namePos += 4;
430                     strcpy(featureExtraTagString+namePos, BAD_CAST featureExtraTag[i].value);
431                     namePos += lineValueLen;
432                     strcpy(featureExtraTagString+(namePos++), "\"");
433                 }
434             }
435             paramValues[6] = (const char *)featureExtraTagString;
436
437             paramValues[7] = (const char *)feature.adminLevel;
438             paramValues[8] = (const char *)feature.houseNumber;
439             paramValues[9] = (const char *)feature.rankAddress;
440             paramValues[10] = (const char *)feature.rankSearch;
441             paramValues[11] = (const char *)feature.geometry;
442             res = PQexecPrepared(conn, "placex_insert", 12, paramValues, NULL, NULL, 0);
443             if (PQresultStatus(res) != PGRES_COMMAND_OK)
444             {
445                 fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
446                 PQclear(res);
447                 exit(EXIT_FAILURE);
448             }
449             PQclear(res);
450
451             for (i = 0; i < featureAddressLines; i++)
452             {
453                 // insert into place_address
454                 paramValues[0] = (const char *)place_id;
455                 paramValues[1] = (const char *)featureAddress[i].distance;
456                 paramValues[2] = (const char *)featureAddress[i].type;
457                 paramValues[3] = (const char *)featureAddress[i].id;
458                 paramValues[4] = (const char *)featureAddress[i].key;
459                 paramValues[5] = (const char *)featureAddress[i].value;
460                 paramValues[6] = (const char *)featureAddress[i].isAddress;
461                 res = PQexecPrepared(conn, "place_addressline_insert", 7, paramValues, NULL, NULL, 0);
462                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
463                 {
464                     fprintf(stderr, "place_addressline_insert: INSERT failed: %s", PQerrorMessage(conn));
465                     PQclear(res);
466                     exit(EXIT_FAILURE);
467                 }
468                 PQclear(res);
469
470                 xmlFree(featureAddress[i].type);
471                 xmlFree(featureAddress[i].id);
472                 xmlFree(featureAddress[i].key);
473                 xmlFree(featureAddress[i].value);
474                 xmlFree(featureAddress[i].distance);
475             }
476
477             if (featureNameLines)
478             {
479                 paramValues[0] = (const char *)place_id;
480                 res = PQexecPrepared(conn, "search_name_insert", 1, paramValues, NULL, NULL, 0);
481                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
482                 {
483                     fprintf(stderr, "search_name_insert: INSERT failed: %s", PQerrorMessage(conn));
484                     PQclear(res);
485                     exit(EXIT_FAILURE);
486                 }
487                 PQclear(res);
488             }
489
490             partionQueryName = xmlHashLookup2(partionTableTagsHash, feature.key, feature.value);
491             if (partionQueryName)
492             {
493                 // insert into partition table
494                 paramValues[0] = (const char *)place_id;
495                 paramValues[1] = (const char *)feature.geometry;
496                 res = PQexecPrepared(conn, partionQueryName, 2, paramValues, NULL, NULL, 0);
497                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
498                 {
499                     fprintf(stderr, "%s: INSERT failed: %s", partionQueryName, PQerrorMessage(conn));
500                     PQclear(res);
501                     exit(EXIT_FAILURE);
502                 }
503                 PQclear(res);
504
505             }
506
507         }
508         else
509         {
510             for (i = 0; i < featureAddressLines; i++)
511             {
512                 xmlFree(featureAddress[i].type);
513                 xmlFree(featureAddress[i].id);
514                 xmlFree(featureAddress[i].key);
515                 xmlFree(featureAddress[i].value);
516                 xmlFree(featureAddress[i].distance);
517             }
518         }
519
520         xmlFree(feature.type);
521         xmlFree(feature.id);
522         xmlFree(feature.key);
523         xmlFree(feature.value);
524         xmlFree(feature.rankAddress);
525         xmlFree(feature.rankSearch);
526 //              if (feature.name) xmlFree(feature.name);
527         if (feature.countryCode) xmlFree(feature.countryCode);
528         if (feature.adminLevel) xmlFree(feature.adminLevel);
529         if (feature.houseNumber) xmlFree(feature.houseNumber);
530         if (feature.geometry) xmlFree(feature.geometry);
531
532         PQclear(resPlaceID);
533     }
534 }
535
536 static void processNode(xmlTextReaderPtr reader)
537 {
538     xmlChar *name;
539     name = xmlTextReaderName(reader);
540     if (name == NULL)
541     {
542         name = xmlStrdup(BAD_CAST "--");
543     }
544
545     switch (xmlTextReaderNodeType(reader))
546     {
547     case XML_READER_TYPE_ELEMENT:
548         StartElement(reader, name);
549         if (xmlTextReaderIsEmptyElement(reader))
550             EndElement(reader, name); /* No end_element for self closing tags! */
551         break;
552     case XML_READER_TYPE_END_ELEMENT:
553         EndElement(reader, name);
554         break;
555     case XML_READER_TYPE_TEXT:
556     case XML_READER_TYPE_CDATA:
557     case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
558         /* Ignore */
559         break;
560     default:
561         fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
562         break;
563     }
564
565     xmlFree(name);
566 }
567
568 int nominatim_import(const char *conninfo, const char *partionTagsFilename, const char *filename)
569 {
570     xmlTextReaderPtr    reader;
571     int                                 ret = 0;
572     PGresult *                  res;
573     FILE *                              partionTagsFile;
574     char *                              partionQueryName;
575     char                                partionQuerySQL[1024];
576
577     conn = PQconnectdb(conninfo);
578     if (PQstatus(conn) != CONNECTION_OK)
579     {
580         fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
581         exit(EXIT_FAILURE);
582     }
583
584     partionTableTagsHash = xmlHashCreate(200);
585
586     partionTagsFile = fopen(partionTagsFilename, "rt");
587     if (!partionTagsFile)
588     {
589         fprintf(stderr, "Unable to read partition tags file: %s\n", partionTagsFilename);
590         exit(EXIT_FAILURE);
591     }
592
593     char buffer[1024], osmkey[256], osmvalue[256];
594     int fields;
595     while (fgets(buffer, sizeof(buffer), partionTagsFile) != NULL)
596     {
597         fields = sscanf( buffer, "%23s %63s", osmkey, osmvalue );
598
599         if ( fields <= 0 ) continue;
600
601         if ( fields != 2  )
602         {
603             fprintf( stderr, "Error partition file\n");
604             exit_nicely();
605         }
606         partionQueryName = malloc(strlen("partition_insert_")+strlen(osmkey)+strlen(osmvalue)+2);
607         strcpy(partionQueryName, "partition_insert_");
608         strcat(partionQueryName, osmkey);
609         strcat(partionQueryName, "_");
610         strcat(partionQueryName, osmvalue);
611
612         strcpy(partionQuerySQL, "insert into place_classtype_");
613         strcat(partionQuerySQL, osmkey);
614         strcat(partionQuerySQL, "_");
615         strcat(partionQuerySQL, osmvalue);
616         strcat(partionQuerySQL, " (place_id, centroid) values ($1, ST_Centroid(st_setsrid($2, 4326)))");
617
618         res = PQprepare(conn, partionQueryName, partionQuerySQL, 2, NULL);
619         if (PQresultStatus(res) != PGRES_COMMAND_OK)
620         {
621             fprintf(stderr, "Failed to prepare %s: %s\n", partionQueryName, PQerrorMessage(conn));
622             exit(EXIT_FAILURE);
623         }
624
625         xmlHashAddEntry2(partionTableTagsHash, BAD_CAST osmkey, BAD_CAST osmvalue, BAD_CAST partionQueryName);
626     }
627
628     res = PQprepare(conn, "get_new_place_id",
629                     "select nextval('seq_place')",
630                     0, NULL);
631     if (PQresultStatus(res) != PGRES_COMMAND_OK)
632     {
633         fprintf(stderr, "Failed to prepare get_new_place_id: %s\n", PQerrorMessage(conn));
634         exit(EXIT_FAILURE);
635     }
636
637     res = PQprepare(conn, "get_place_id",
638                     "select place_id from placex where osm_type = $1 and osm_id = $2 and class = $3 and type = $4",
639                     4, NULL);
640     if (PQresultStatus(res) != PGRES_COMMAND_OK)
641     {
642         fprintf(stderr, "Failed to prepare get_place_id: %s\n", PQerrorMessage(conn));
643         exit(EXIT_FAILURE);
644     }
645
646     res = PQprepare(conn, "placex_insert",
647                     "insert into placex (place_id,osm_type,osm_id,class,type,name,extratags,admin_level,housenumber,rank_address,rank_search,geometry) "
648                     "values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, st_setsrid($12, 4326))",
649                     12, NULL);
650     if (PQresultStatus(res) != PGRES_COMMAND_OK)
651     {
652         fprintf(stderr, "Failed to prepare placex_insert: %s\n", PQerrorMessage(conn));
653         exit(EXIT_FAILURE);
654     }
655
656     res = PQprepare(conn, "search_name_insert",
657                     "insert into search_name (place_id, search_rank, address_rank, country_code, name_vector, nameaddress_vector, centroid) "
658                     "select place_id, rank_address, rank_search, country_code, make_keywords(name), "
659                     "(select uniq(sort(array_agg(name_vector))) from place_addressline join search_name on "
660                     "(address_place_id = search_name.place_id) where place_addressline.place_id = $1 ), st_centroid(geometry) from placex "
661                     "where place_id = $1",
662                     1, NULL);
663     if (PQresultStatus(res) != PGRES_COMMAND_OK)
664     {
665         fprintf(stderr, "Failed to prepare search_name_insert: %s\n", PQerrorMessage(conn));
666         exit(EXIT_FAILURE);
667     }
668
669     res = PQprepare(conn, "place_addressline_insert",
670                     "insert into place_addressline (place_id, address_place_id, fromarea, isaddress, distance, cached_rank_address) "
671                     "select $1, place_id, false, $7, $2, rank_address from placex where osm_type = $3 and osm_id = $4 and class = $5 and type = $6",
672                     7, NULL);
673     if (PQresultStatus(res) != PGRES_COMMAND_OK)
674     {
675         fprintf(stderr, "Failed to prepare place_addressline_insert: %s\n", PQerrorMessage(conn));
676         exit(EXIT_FAILURE);
677     }
678
679     res = PQprepare(conn, "placex_delete",
680                     "delete from placex where place_id = $1",
681                     1, NULL);
682     if (PQresultStatus(res) != PGRES_COMMAND_OK)
683     {
684         fprintf(stderr, "Failed to prepare placex_delete: %s\n", PQerrorMessage(conn));
685         exit(EXIT_FAILURE);
686     }
687
688     res = PQprepare(conn, "search_name_delete",
689                     "delete from search_name where place_id = $1",
690                     1, NULL);
691     if (PQresultStatus(res) != PGRES_COMMAND_OK)
692     {
693         fprintf(stderr, "Failed to prepare search_name_delete: %s\n", PQerrorMessage(conn));
694         exit(EXIT_FAILURE);
695     }
696
697     res = PQprepare(conn, "place_addressline_delete",
698                     "delete from place_addressline where place_id = $1",
699                     1, NULL);
700     if (PQresultStatus(res) != PGRES_COMMAND_OK)
701     {
702         fprintf(stderr, "Failed to prepare place_addressline_delete: %s\n", PQerrorMessage(conn));
703         exit(EXIT_FAILURE);
704     }
705
706     featureCount = 0;
707
708     reader = inputUTF8(filename);
709
710     if (reader == NULL)
711     {
712         fprintf(stderr, "Unable to open %s\n", filename);
713         return 1;
714     }
715
716     ret = xmlTextReaderRead(reader);
717     while (ret == 1)
718     {
719         processNode(reader);
720         ret = xmlTextReaderRead(reader);
721     }
722     if (ret != 0)
723     {
724         fprintf(stderr, "%s : failed to parse\n", filename);
725         return ret;
726     }
727
728     xmlFreeTextReader(reader);
729     xmlHashFree(partionTableTagsHash, NULL);
730
731     return 0;
732 }