]> git.openstreetmap.org Git - nominatim.git/blobdiff - nominatim/import.c
force utf-8 encoding when reading logfile
[nominatim.git] / nominatim / import.c
index 591ff4ede7675d9d05a20793df4ab1e027360c9b..b9341608a42346884ccb89aeb179805dc4a89c45 100644 (file)
 typedef enum { FILETYPE_NONE, FILETYPE_STRUCTUREDV0P1 } filetypes_t;
 typedef enum { FILEMODE_NONE, FILEMODE_ADD, FILEMODE_UPDATE, FILEMODE_DELETE } filemodes_t;
 
-#define MAX_FEATUREADDRESS 500
-#define MAX_FEATURENAMES 1000
-#define MAX_FEATUREEXTRATAGS 100
-#define MAX_FEATURENAMESTRING 100000
-#define MAX_FEATUREEXTRATAGSTRING 50000
+#define MAX_FEATUREADDRESS 5000
+#define MAX_FEATURENAMES 10000
+#define MAX_FEATUREEXTRATAGS 10000
+#define MAX_FEATURENAMESTRING 1000000
+#define MAX_FEATUREEXTRATAGSTRING 500000
 
 struct feature_address
 {
@@ -42,7 +42,7 @@ struct feature_tag
 
 struct feature
 {
-    int                        placeID;
+    xmlChar *   placeID;
     xmlChar *  type;
     xmlChar *  id;
     xmlChar *  key;
@@ -50,6 +50,9 @@ struct feature
     xmlChar *  rankAddress;
     xmlChar *  rankSearch;
     xmlChar *  countryCode;
+    xmlChar *  parentPlaceID;
+    xmlChar *  parentType;
+    xmlChar *  parentID;
     xmlChar *  adminLevel;
     xmlChar *  houseNumber;
     xmlChar *  geometry;
@@ -67,9 +70,12 @@ int                                  featureNameLines = 0;
 int                                    featureExtraTagLines = 0;
 int                                    featureCount = 0;
 xmlHashTablePtr                partionTableTagsHash;
+xmlHashTablePtr                partionTableTagsHashDelete;
 char                                   featureNameString[MAX_FEATURENAMESTRING];
 char                                   featureExtraTagString[MAX_FEATUREEXTRATAGSTRING];
 
+extern int verbose;
+
 void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
 {
     char * value;
@@ -92,7 +98,7 @@ void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
             }
             else
             {
-                fprintf( stderr, "Unknown osmStructured version %f\n", version );
+                fprintf( stderr, "Unknown osmStructured version %f (%s)\n", version, value );
                 exit_nicely();
             }
         }
@@ -127,6 +133,7 @@ void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
 
     if (xmlStrEqual(name, BAD_CAST "feature"))
     {
+        feature.placeID = xmlTextReaderGetAttribute(reader, BAD_CAST "place_id");
         feature.type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
         feature.id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
         feature.key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
@@ -134,38 +141,56 @@ void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
         feature.rankAddress = xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
         feature.rankSearch = xmlTextReaderGetAttribute(reader, BAD_CAST "importance");
 
+        feature.parentPlaceID = xmlTextReaderGetAttribute(reader, BAD_CAST "parent_place_id");
+/*
+       if (strlen(feature.parentPlaceID) == 0)
+       {
+               xmlFree(feature.parentPlaceID);
+               feature.parentPlaceID = NULL;
+       }
+*/
+        feature.parentType = xmlTextReaderGetAttribute(reader, BAD_CAST "parent_type");
+        feature.parentID = xmlTextReaderGetAttribute(reader, BAD_CAST "parent_id");
+
         feature.countryCode = NULL;
         feature.adminLevel = NULL;
         feature.houseNumber = NULL;
         feature.geometry = NULL;
         featureAddressLines = 0;
         featureNameLines = 0;
+        featureExtraTagLines = 0;
 
         return;
     }
     if (xmlStrEqual(name, BAD_CAST "names")) return;
     if (xmlStrEqual(name, BAD_CAST "name"))
     {
-        featureName[featureNameLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
-        featureName[featureNameLines].value = xmlTextReaderReadString(reader);
-        featureNameLines++;
-        if (featureNameLines >= MAX_FEATURENAMES)
+        if (featureNameLines < MAX_FEATURENAMES)
         {
-            fprintf( stderr, "Too many name elements\n");
-            exit_nicely();
+               featureName[featureNameLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
+           featureName[featureNameLines].value = xmlTextReaderReadString(reader);
+               featureNameLines++;
+               }
+               else
+               {
+            fprintf( stderr, "Too many name elements (%s%s)\n", feature.type, feature.id);
+//            exit_nicely();
         }
         return;
     }
     if (xmlStrEqual(name, BAD_CAST "tags")) return;
     if (xmlStrEqual(name, BAD_CAST "tag"))
     {
-        featureExtraTag[featureExtraTagLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
-        featureExtraTag[featureExtraTagLines].value = xmlTextReaderReadString(reader);
-        featureExtraTagLines++;
-        if (featureExtraTagLines >= MAX_FEATUREEXTRATAGS)
+        if (featureExtraTagLines < MAX_FEATUREEXTRATAGS)
+               {
+               featureExtraTag[featureExtraTagLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
+           featureExtraTag[featureExtraTagLines].value = xmlTextReaderReadString(reader);
+               featureExtraTagLines++;
+               }
+               else
         {
-            fprintf( stderr, "Too many extra tag elements\n");
-            exit_nicely();
+            fprintf( stderr, "Too many extra tag elements (%s%s)\n", feature.type, feature.id);
+//            exit_nicely();
         }
         return;
     }
@@ -261,36 +286,39 @@ void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
     }
     if (isAddressLine)
     {
-        value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
-        if (!value)
-        {
-            fprintf( stderr, "Address element missing rank\n");
-            exit_nicely();
-        }
-        featureAddress[featureAddressLines].rankAddress =  atoi(value);
-        xmlFree(value);
-
-        value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "isaddress");
-        if (!value)
+        if (featureAddressLines < MAX_FEATUREADDRESS)
+               {
+               value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
+           if (!value)
+               {
+               fprintf( stderr, "Address element missing rank\n");
+                   exit_nicely();
+               }
+           featureAddress[featureAddressLines].rankAddress =  atoi(value);
+               xmlFree(value);
+
+               value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "isaddress");
+           if (!value)
+               {
+                   fprintf( stderr, "Address element missing rank\n");
+               exit_nicely();
+               }
+               if (*value == 't') strcpy(featureAddress[featureAddressLines].isAddress, "t");
+           else strcpy(featureAddress[featureAddressLines].isAddress, "f");
+               xmlFree(value);
+
+               featureAddress[featureAddressLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
+           featureAddress[featureAddressLines].id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
+               featureAddress[featureAddressLines].key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
+               featureAddress[featureAddressLines].value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
+           featureAddress[featureAddressLines].distance = xmlTextReaderGetAttribute(reader, BAD_CAST "distance");
+       
+           featureAddressLines++;
+               }
+               else
         {
-            fprintf( stderr, "Address element missing rank\n");
-            exit_nicely();
-        }
-        if (*value == 't') strcpy(featureAddress[featureAddressLines].isAddress, "t");
-        else strcpy(featureAddress[featureAddressLines].isAddress, "f");
-        xmlFree(value);
-
-        featureAddress[featureAddressLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
-        featureAddress[featureAddressLines].id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
-        featureAddress[featureAddressLines].key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
-        featureAddress[featureAddressLines].value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
-        featureAddress[featureAddressLines].distance = xmlTextReaderGetAttribute(reader, BAD_CAST "distance");
-
-        featureAddressLines++;
-        if (featureAddressLines >= MAX_FEATUREADDRESS)
-        {
-            fprintf( stderr, "Too many address elements\n");
-            exit_nicely();
+            fprintf( stderr, "Too many address elements (%s%s)\n", feature.type, feature.id);
+//            exit_nicely();
         }
 
         return;
@@ -301,8 +329,7 @@ void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
 void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
 {
     PGresult *                 res;
-    PGresult *                 resPlaceID;
-    const char *       paramValues[11];
+    const char *       paramValues[14];
     char *                     place_id;
     char *                     partionQueryName;
     int i, namePos, lineTypeLen, lineValueLen;
@@ -311,7 +338,7 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
     {
         featureCount++;
         if (featureCount % 1000 == 0) printf("feature %i(k)\n", featureCount/1000);
-
+/*
         if (fileMode == FILEMODE_ADD)
         {
             resPlaceID = PQexecPrepared(conn, "get_new_place_id", 0, NULL, NULL, NULL, 0);
@@ -336,11 +363,13 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
                 exit(EXIT_FAILURE);
             }
         }
-        place_id = PQgetvalue(resPlaceID, 0, 0);
+*/
+        place_id = (char *)feature.placeID;
 
-        if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_DELETE)
+        if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_DELETE || fileMode == FILEMODE_ADD)
         {
             paramValues[0] = (const char *)place_id;
+            if (verbose) fprintf(stderr, "placex_delete: %s\n", paramValues[0]);
             res = PQexecPrepared(conn, "placex_delete", 1, paramValues, NULL, NULL, 0);
             if (PQresultStatus(res) != PGRES_COMMAND_OK)
             {
@@ -350,6 +379,7 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
             }
             PQclear(res);
 
+            if (verbose) fprintf(stderr, "search_name_delete: %s\n", paramValues[0]);
             res = PQexecPrepared(conn, "search_name_delete", 1, paramValues, NULL, NULL, 0);
             if (PQresultStatus(res) != PGRES_COMMAND_OK)
             {
@@ -359,6 +389,7 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
             }
             PQclear(res);
 
+            if (verbose) fprintf(stderr, "place_addressline_delete: %s\n", paramValues[0]);
             res = PQexecPrepared(conn, "place_addressline_delete", 1, paramValues, NULL, NULL, 0);
             if (PQresultStatus(res) != PGRES_COMMAND_OK)
             {
@@ -367,6 +398,19 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
                 exit(EXIT_FAILURE);
             }
             PQclear(res);
+
+            partionQueryName = xmlHashLookup2(partionTableTagsHashDelete, feature.key, feature.value);
+            if (partionQueryName)
+            {
+                res = PQexecPrepared(conn, partionQueryName, 1, paramValues, NULL, NULL, 0);
+                if (PQresultStatus(res) != PGRES_COMMAND_OK)
+                {
+                    fprintf(stderr, "%s: DELETE failed: %s", partionQueryName, PQerrorMessage(conn));
+                    PQclear(res);
+                    exit(EXIT_FAILURE);
+                }
+                PQclear(res);
+            }
         }
 
         if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_ADD)
@@ -386,8 +430,8 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
                 lineValueLen = 0;
                 for (i = 0; i < featureNameLines; i++)
                 {
-                    lineTypeLen = strlen(BAD_CAST featureName[i].type);
-                    lineValueLen = strlen(BAD_CAST featureName[i].value);
+                    lineTypeLen = (int)strlen((char *) featureName[i].type);
+                    lineValueLen = (int)strlen((char *) featureName[i].value);
                     if (namePos+lineTypeLen+lineValueLen+7 > MAX_FEATURENAMESTRING)
                     {
                         fprintf(stderr, "feature name too long: %s", (const char *)featureName[i].value);
@@ -395,17 +439,22 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
                     }
                     if (namePos) strcpy(featureNameString+(namePos++), ",");
                     strcpy(featureNameString+(namePos++), "\"");
-                    strcpy(featureNameString+namePos, BAD_CAST featureName[i].type);
+                    strcpy(featureNameString+namePos, (char*) featureName[i].type);
                     namePos += lineTypeLen;
                     strcpy(featureNameString+namePos, "\"=>\"");
                     namePos += 4;
-                    strcpy(featureNameString+namePos, BAD_CAST featureName[i].value);
+                    strcpy(featureNameString+namePos, (char *) featureName[i].value);
                     namePos += lineValueLen;
                     strcpy(featureNameString+(namePos++), "\"");
+
+                    xmlFree(featureName[i].type);
+                    xmlFree(featureName[i].value);
                 }
             }
             paramValues[5] = (const char *)featureNameString;
 
+            paramValues[6] = (const char *)feature.countryCode;
+
             featureExtraTagString[0] = 0;
             if (featureExtraTagLines)
             {
@@ -414,8 +463,8 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
                 lineValueLen = 0;
                 for (i = 0; i < featureExtraTagLines; i++)
                 {
-                    lineTypeLen = strlen(BAD_CAST featureExtraTag[i].type);
-                    lineValueLen = strlen(BAD_CAST featureExtraTag[i].value);
+                    lineTypeLen = strlen((char *) featureExtraTag[i].type);
+                    lineValueLen = strlen((char *) featureExtraTag[i].value);
                     if (namePos+lineTypeLen+lineValueLen+7 > MAX_FEATUREEXTRATAGSTRING)
                     {
                         fprintf(stderr, "feature extra tag too long: %s", (const char *)featureExtraTag[i].value);
@@ -423,45 +472,61 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
                     }
                     if (namePos) strcpy(featureExtraTagString+(namePos++),",");
                     strcpy(featureExtraTagString+(namePos++), "\"");
-                    strcpy(featureExtraTagString+namePos, BAD_CAST featureExtraTag[i].type);
+                    strcpy(featureExtraTagString+namePos, (char *) featureExtraTag[i].type);
                     namePos += lineTypeLen;
                     strcpy(featureExtraTagString+namePos, "\"=>\"");
                     namePos += 4;
-                    strcpy(featureExtraTagString+namePos, BAD_CAST featureExtraTag[i].value);
+                    strcpy(featureExtraTagString+namePos, (char *) featureExtraTag[i].value);
                     namePos += lineValueLen;
                     strcpy(featureExtraTagString+(namePos++), "\"");
+
+                    xmlFree(featureExtraTag[i].type);
+                    xmlFree(featureExtraTag[i].value);
                 }
             }
-            paramValues[6] = (const char *)featureExtraTagString;
-
-            paramValues[7] = (const char *)feature.adminLevel;
-            paramValues[8] = (const char *)feature.houseNumber;
-            paramValues[9] = (const char *)feature.rankAddress;
-            paramValues[10] = (const char *)feature.rankSearch;
-            paramValues[11] = (const char *)feature.geometry;
-            res = PQexecPrepared(conn, "placex_insert", 12, paramValues, NULL, NULL, 0);
-            if (PQresultStatus(res) != PGRES_COMMAND_OK)
+            paramValues[7] = (const char *)featureExtraTagString;
+
+            if (strlen(feature.parentPlaceID) == 0)
+                paramValues[8] = "0";
+            else
+                paramValues[8] = (const char *)feature.parentPlaceID;
+
+            paramValues[9] = (const char *)feature.adminLevel;
+            paramValues[10] = (const char *)feature.houseNumber;
+            paramValues[11] = (const char *)feature.rankAddress;
+            paramValues[12] = (const char *)feature.rankSearch;
+            paramValues[13] = (const char *)feature.geometry;
+            if (strlen(paramValues[3]) && strlen(paramValues[13]))
             {
-                fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
-                PQclear(res);
-                exit(EXIT_FAILURE);
+                if (verbose) fprintf(stderr, "placex_insert: %s\n", paramValues[0]);
+                res = PQexecPrepared(conn, "placex_insert", 14, paramValues, NULL, NULL, 0);
+                if (PQresultStatus(res) != PGRES_COMMAND_OK)
+                {
+                    fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
+                    fprintf(stderr, "index_placex: INSERT failed: %s %s %s", paramValues[0], paramValues[1], paramValues[2]);
+                    PQclear(res);
+                    exit(EXIT_FAILURE);
+               }
+               PQclear(res);
             }
-            PQclear(res);
 
             for (i = 0; i < featureAddressLines; i++)
             {
                 // insert into place_address
                 paramValues[0] = (const char *)place_id;
                 paramValues[1] = (const char *)featureAddress[i].distance;
+                if (paramValues[1] == NULL || strlen(paramValues[1]) == 0) paramValues[1] = "0";
                 paramValues[2] = (const char *)featureAddress[i].type;
                 paramValues[3] = (const char *)featureAddress[i].id;
                 paramValues[4] = (const char *)featureAddress[i].key;
                 paramValues[5] = (const char *)featureAddress[i].value;
                 paramValues[6] = (const char *)featureAddress[i].isAddress;
+                if (verbose) fprintf(stderr, "placex_insert: %s %s\n", paramValues[2], paramValues[3]);
                 res = PQexecPrepared(conn, "place_addressline_insert", 7, paramValues, NULL, NULL, 0);
                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
                 {
                     fprintf(stderr, "place_addressline_insert: INSERT failed: %s", PQerrorMessage(conn));
+                    fprintf(stderr, "(%s,%s,%s,%s,%s,%s,%s)",paramValues[0],paramValues[1],paramValues[2],paramValues[3],paramValues[4],paramValues[5],paramValues[6]);
                     PQclear(res);
                     exit(EXIT_FAILURE);
                 }
@@ -476,15 +541,33 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
 
             if (featureNameLines)
             {
-                paramValues[0] = (const char *)place_id;
-                res = PQexecPrepared(conn, "search_name_insert", 1, paramValues, NULL, NULL, 0);
-                if (PQresultStatus(res) != PGRES_COMMAND_OK)
-                {
-                    fprintf(stderr, "search_name_insert: INSERT failed: %s", PQerrorMessage(conn));
+                if (strlen(feature.parentPlaceID) > 0 && featureAddressLines == 0)
+               {
+                    paramValues[0] = (const char *)place_id;
+                    paramValues[1] = feature.parentPlaceID;
+                    if (verbose) fprintf(stderr, "search_name_from_parent_insert: INSERT %s %s\n", paramValues[0], paramValues[1]);
+                    res = PQexecPrepared(conn, "search_name_from_parent_insert", 2, paramValues, NULL, NULL, 0);
+                    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+                    {
+                        fprintf(stderr, "search_name_from_parent_insert: INSERT failed: %s", PQerrorMessage(conn));
+                        PQclear(res);
+                        exit(EXIT_FAILURE);
+                    }
+                    PQclear(res);
+               }
+               else
+               {
+                    paramValues[0] = (const char *)place_id;
+                    if (verbose) fprintf(stderr, "search_name_insert: INSERT %s\n", paramValues[0]);
+                    res = PQexecPrepared(conn, "search_name_insert", 1, paramValues, NULL, NULL, 0);
+                    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+                    {
+                        fprintf(stderr, "search_name_insert: INSERT failed: %s", PQerrorMessage(conn));
+                        PQclear(res);
+                        exit(EXIT_FAILURE);
+                    }
                     PQclear(res);
-                    exit(EXIT_FAILURE);
                 }
-                PQclear(res);
             }
 
             partionQueryName = xmlHashLookup2(partionTableTagsHash, feature.key, feature.value);
@@ -501,7 +584,6 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
                     exit(EXIT_FAILURE);
                 }
                 PQclear(res);
-
             }
 
         }
@@ -517,19 +599,23 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
             }
         }
 
+        xmlFree(feature.placeID);
         xmlFree(feature.type);
         xmlFree(feature.id);
         xmlFree(feature.key);
         xmlFree(feature.value);
         xmlFree(feature.rankAddress);
         xmlFree(feature.rankSearch);
-//             if (feature.name) xmlFree(feature.name);
         if (feature.countryCode) xmlFree(feature.countryCode);
+       if (feature.parentPlaceID) xmlFree(feature.parentPlaceID);
+       if (feature.parentType) xmlFree(feature.parentType);
+       if (feature.parentID) xmlFree(feature.parentID);
+//             if (feature.name) xmlFree(feature.name);
         if (feature.adminLevel) xmlFree(feature.adminLevel);
         if (feature.houseNumber) xmlFree(feature.houseNumber);
         if (feature.geometry) xmlFree(feature.geometry);
 
-        PQclear(resPlaceID);
+//        PQclear(resPlaceID);
     }
 }
 
@@ -582,6 +668,7 @@ int nominatim_import(const char *conninfo, const char *partionTagsFilename, cons
     }
 
     partionTableTagsHash = xmlHashCreate(200);
+    partionTableTagsHashDelete = xmlHashCreate(200);
 
     partionTagsFile = fopen(partionTagsFilename, "rt");
     if (!partionTagsFile)
@@ -623,6 +710,27 @@ int nominatim_import(const char *conninfo, const char *partionTagsFilename, cons
         }
 
         xmlHashAddEntry2(partionTableTagsHash, BAD_CAST osmkey, BAD_CAST osmvalue, BAD_CAST partionQueryName);
+
+        partionQueryName = malloc(strlen("partition_delete_")+strlen(osmkey)+strlen(osmvalue)+2);
+        strcpy(partionQueryName, "partition_delete_");
+        strcat(partionQueryName, osmkey);
+        strcat(partionQueryName, "_");
+        strcat(partionQueryName, osmvalue);
+
+        strcpy(partionQuerySQL, "delete from place_classtype_");
+        strcat(partionQuerySQL, osmkey);
+        strcat(partionQuerySQL, "_");
+        strcat(partionQuerySQL, osmvalue);
+        strcat(partionQuerySQL, " where place_id = $1::integer");
+
+        res = PQprepare(conn, partionQueryName, partionQuerySQL, 1, NULL);
+        if (PQresultStatus(res) != PGRES_COMMAND_OK)
+        {
+            fprintf(stderr, "Failed to prepare %s: %s\n", partionQueryName, PQerrorMessage(conn));
+            exit(EXIT_FAILURE);
+        }
+
+        xmlHashAddEntry2(partionTableTagsHashDelete, BAD_CAST osmkey, BAD_CAST osmvalue, BAD_CAST partionQueryName);
     }
 
     res = PQprepare(conn, "get_new_place_id",
@@ -644,8 +752,8 @@ int nominatim_import(const char *conninfo, const char *partionTagsFilename, cons
     }
 
     res = PQprepare(conn, "placex_insert",
-                    "insert into placex (place_id,osm_type,osm_id,class,type,name,extratags,admin_level,housenumber,rank_address,rank_search,geometry) "
-                    "values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, st_setsrid($12, 4326))",
+                    "insert into placex (place_id,osm_type,osm_id,class,type,name,country_code,extratags,parent_place_id,admin_level,housenumber,rank_address,rank_search,geometry) "
+                    "values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, st_setsrid($14, 4326))",
                     12, NULL);
     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     {
@@ -655,11 +763,26 @@ int nominatim_import(const char *conninfo, const char *partionTagsFilename, cons
 
     res = PQprepare(conn, "search_name_insert",
                     "insert into search_name (place_id, search_rank, address_rank, country_code, name_vector, nameaddress_vector, centroid) "
-                    "select place_id, rank_address, rank_search, country_code, make_keywords(name), "
-                    "(select uniq(sort(array_agg(name_vector))) from place_addressline join search_name on "
-                    "(address_place_id = search_name.place_id) where place_addressline.place_id = $1 ), st_centroid(geometry) from placex "
+                    "select place_id, rank_search, rank_address, country_code, make_keywords(name), "
+                    "(select uniq(sort(array_agg(parent_search_name.name_vector))) from search_name as parent_search_name where place_id in "
+                     "(select distinct address_place_id from place_addressline where place_addressline.place_id = $1 limit 1000)"
+                    "), st_centroid(geometry) from placex "
                     "where place_id = $1",
                     1, NULL);
+
+    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+    {
+        fprintf(stderr, "Failed to prepare search_name_insert: %s\n", PQerrorMessage(conn));
+        exit(EXIT_FAILURE);
+    }
+
+    res = PQprepare(conn, "search_name_from_parent_insert",
+                    "insert into search_name (place_id, search_rank, address_rank, country_code, name_vector, nameaddress_vector, centroid) "
+                    "select place_id, rank_search, rank_address, country_code, make_keywords(name), "
+                    "(select uniq(sort(name_vector+nameaddress_vector)) from search_name as parent_search_name "
+                    "where parent_search_name.place_id = $2 ), st_centroid(geometry) from placex "
+                    "where place_id = $1",
+                    2, NULL);
     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     {
         fprintf(stderr, "Failed to prepare search_name_insert: %s\n", PQerrorMessage(conn));
@@ -727,6 +850,7 @@ int nominatim_import(const char *conninfo, const char *partionTagsFilename, cons
 
     xmlFreeTextReader(reader);
     xmlHashFree(partionTableTagsHash, NULL);
+    xmlHashFree(partionTableTagsHashDelete, NULL);
 
     return 0;
 }