]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge pull request #1532 from eyusupov/use-extradir
authorSarah Hoffmann <lonvia@denofr.de>
Mon, 28 Oct 2019 22:01:42 +0000 (23:01 +0100)
committerGitHub <noreply@github.com>
Mon, 28 Oct 2019 22:01:42 +0000 (23:01 +0100)
Use ExtraDataPath for country grid

CMakeLists.txt
ChangeLog
docs/CMakeLists.txt
docs/admin/Migration.md
docs/mkdocs.yml
docs/styles.css [new file with mode: 0644]
lib/ParameterParser.php
osm2pgsql
test/php/Nominatim/ParameterParserTest.php
utils/specialphrases.php

index 163b04943c68f8b39cf368ae94647ec2f1de761c..88b0405187e6192780d42e9dc64363c83364fd7e 100644 (file)
@@ -19,7 +19,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
 project(nominatim)
 
 set(NOMINATIM_VERSION_MAJOR 3)
-set(NOMINATIM_VERSION_MINOR 3)
+set(NOMINATIM_VERSION_MINOR 4)
 set(NOMINATIM_VERSION_PATCH 0)
 
 set(NOMINATIM_VERSION "${NOMINATIM_VERSION_MAJOR}.${NOMINATIM_VERSION_MINOR}.${NOMINATIM_VERSION_PATCH}")
index 1927b5901cc950e3d89cadc19ec644151645c90f..db8f9bba86dfb41f33ceca3e77f141fd4dbb14b4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+3.4.0
+
+ * increase required version for PostgreSQL(9.3), PostGIS(2.2) and PHP(7.0)
+ * better error reporting for out-of-memory errors
+ * exclude postcode ranges separated by colon from centre point calculation
+ * update osm2pgsql, better handling of imports without flatnode file
+ * switch to more efficient algorithm for word set computation
+ * use only boundries for country and state parts of addresses
+ * improve updates of addresses with housenumbers and interpolations
+ * remove country from place_addressline table and use country_code instead
+ * optimise indexes on search_name partition tables
+ * improve searching of attached streets for large objects like airports
+ * drop support for python 2
+ * new scripts for importing Wikidata for importance
+ * create and drop indexes concurrently to not clash with auto vacuum
+ * various documentation improvements
+
+
 3.3.0
 
  * zoom 17 in reverse now zooms in on minor streets
index fb35cc1d5e75b0182058cdfb5876bfba8521ec48..bdba63db189ec3f9205f808d1fcc935e7a45b44b 100644 (file)
@@ -13,6 +13,7 @@ ADD_CUSTOM_TARGET(doc
    COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/api ${CMAKE_CURRENT_BINARY_DIR}/api
    COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/index.md ${CMAKE_CURRENT_BINARY_DIR}/index.md
    COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/extra.css ${CMAKE_CURRENT_BINARY_DIR}/extra.css
+   COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/styles.css ${CMAKE_CURRENT_BINARY_DIR}/styles.css
    COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/data-sources/overview.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/overview.md
    COMMAND ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/data-sources/us-tiger/README.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/US-Tiger.md
    COMMAND ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/data-sources/gb-postcodes/README.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/GB-Postcodes.md
index c5a05d9afec79b93f5c81439847071c1da92c852..f3668357fd1ffa36b5f595710f4e53d781bb1526 100644 (file)
@@ -6,7 +6,7 @@ to newer versions of Nominatim.
 SQL statements should be executed from the PostgreSQL commandline. Execute
 `psql nominatim` to enter command line mode.
 
-## 3.3.0 -> master
+## 3.3.0 -> 3.4.0
 
 ### Reorganisation of location_area_country table
 
index d87fda7a7e9d42c4b227d0cfdb67c44b6b646dc3..cb00e2e85ef8c3f68479be8c9cf5513330e09859 100644 (file)
@@ -34,8 +34,7 @@ pages:
         - 'Installation on Ubuntu 16' : 'appendix/Install-on-Ubuntu-16.md'
         - 'Installation on Ubuntu 18' : 'appendix/Install-on-Ubuntu-18.md'
 markdown_extensions:
-    - codehilite:
-        use_pygments: False
+    - codehilite
     - toc:
         permalink: 
-extra_css: [extra.css]
+extra_css: [extra.css, styles.css]
diff --git a/docs/styles.css b/docs/styles.css
new file mode 100644 (file)
index 0000000..8ba0a1d
--- /dev/null
@@ -0,0 +1,69 @@
+.codehilite .hll { background-color: #ffffcc }
+.codehilite  { background: #f0f0f0; }
+.codehilite .c { color: #60a0b0; font-style: italic } /* Comment */
+.codehilite .err { /* border: 1px solid #FF0000 */ } /* Error */
+.codehilite .k { color: #007020; font-weight: bold } /* Keyword */
+.codehilite .o { color: #666666 } /* Operator */
+.codehilite .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */
+.codehilite .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
+.codehilite .cp { color: #007020 } /* Comment.Preproc */
+.codehilite .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */
+.codehilite .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
+.codehilite .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
+.codehilite .gd { color: #A00000 } /* Generic.Deleted */
+.codehilite .ge { font-style: italic } /* Generic.Emph */
+.codehilite .gr { color: #FF0000 } /* Generic.Error */
+.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.codehilite .gi { color: #00A000 } /* Generic.Inserted */
+.codehilite .go { color: #888888 } /* Generic.Output */
+.codehilite .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.codehilite .gs { font-weight: bold } /* Generic.Strong */
+.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.codehilite .gt { color: #0044DD } /* Generic.Traceback */
+.codehilite .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.codehilite .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.codehilite .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
+.codehilite .kp { color: #007020 } /* Keyword.Pseudo */
+.codehilite .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.codehilite .kt { color: #902000 } /* Keyword.Type */
+.codehilite .m { color: #40a070 } /* Literal.Number */
+.codehilite .s { color: #4070a0 } /* Literal.String */
+.codehilite .na { color: #4070a0 } /* Name.Attribute */
+.codehilite .nb { color: #007020 } /* Name.Builtin */
+.codehilite .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.codehilite .no { color: #60add5 } /* Name.Constant */
+.codehilite .nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.codehilite .ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.codehilite .ne { color: #007020 } /* Name.Exception */
+.codehilite .nf { color: #06287e } /* Name.Function */
+.codehilite .nl { color: #002070; font-weight: bold } /* Name.Label */
+.codehilite .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.codehilite .nt { color: #062873; font-weight: bold } /* Name.Tag */
+.codehilite .nv { color: #bb60d5 } /* Name.Variable */
+.codehilite .ow { color: #007020; font-weight: bold } /* Operator.Word */
+.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
+.codehilite .mb { color: #40a070 } /* Literal.Number.Bin */
+.codehilite .mf { color: #40a070 } /* Literal.Number.Float */
+.codehilite .mh { color: #40a070 } /* Literal.Number.Hex */
+.codehilite .mi { color: #40a070 } /* Literal.Number.Integer */
+.codehilite .mo { color: #40a070 } /* Literal.Number.Oct */
+.codehilite .sa { color: #4070a0 } /* Literal.String.Affix */
+.codehilite .sb { color: #4070a0 } /* Literal.String.Backtick */
+.codehilite .sc { color: #4070a0 } /* Literal.String.Char */
+.codehilite .dl { color: #4070a0 } /* Literal.String.Delimiter */
+.codehilite .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.codehilite .s2 { color: #4070a0 } /* Literal.String.Double */
+.codehilite .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.codehilite .sh { color: #4070a0 } /* Literal.String.Heredoc */
+.codehilite .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.codehilite .sx { color: #c65d09 } /* Literal.String.Other */
+.codehilite .sr { color: #235388 } /* Literal.String.Regex */
+.codehilite .s1 { color: #4070a0 } /* Literal.String.Single */
+.codehilite .ss { color: #517918 } /* Literal.String.Symbol */
+.codehilite .bp { color: #007020 } /* Name.Builtin.Pseudo */
+.codehilite .fm { color: #06287e } /* Name.Function.Magic */
+.codehilite .vc { color: #bb60d5 } /* Name.Variable.Class */
+.codehilite .vg { color: #bb60d5 } /* Name.Variable.Global */
+.codehilite .vi { color: #bb60d5 } /* Name.Variable.Instance */
+.codehilite .vm { color: #bb60d5 } /* Name.Variable.Magic */
+.codehilite .il { color: #40a070 } /* Literal.Number.Integer.Long */
index ad281d70b634260bfcac15d4656c425d4299e4f1..cb03c6cc7c25c77f3b73f3b2347628a328734f83 100644 (file)
@@ -104,16 +104,16 @@ class ParameterParser
         }
 
         foreach ($aLanguages as $sLanguage => $fLanguagePref) {
-            $aLangPrefOrder['short_name:'.$sLanguage] = 'short_name:'.$sLanguage;
             $aLangPrefOrder['name:'.$sLanguage] = 'name:'.$sLanguage;
         }
-        $aLangPrefOrder['short_name'] = 'short_name';
         $aLangPrefOrder['name'] = 'name';
         $aLangPrefOrder['brand'] = 'brand';
         foreach ($aLanguages as $sLanguage => $fLanguagePref) {
             $aLangPrefOrder['official_name:'.$sLanguage] = 'official_name:'.$sLanguage;
+            $aLangPrefOrder['short_name:'.$sLanguage] = 'short_name:'.$sLanguage;
         }
         $aLangPrefOrder['official_name'] = 'official_name';
+        $aLangPrefOrder['short_name'] = 'short_name';
         $aLangPrefOrder['ref'] = 'ref';
         $aLangPrefOrder['type'] = 'type';
         return $aLangPrefOrder;
index 90e17f0e8c793487ca39cbf95501cd9c5daa33e2..8d9087f1111f4a062158e8e6b10bfbceed90899b 160000 (submodule)
--- a/osm2pgsql
+++ b/osm2pgsql
@@ -1 +1 @@
-Subproject commit 90e17f0e8c793487ca39cbf95501cd9c5daa33e2
+Subproject commit 8d9087f1111f4a062158e8e6b10bfbceed90899b
index ee2f5e1897d8652cf3d7bef9c2a034b1aaba6a72..75f6b276ae19fd5bcd143f399016fff36742a97e 100644 (file)
@@ -175,73 +175,73 @@ class ParameterParserTest extends \PHPUnit\Framework\TestCase
     {
         $oParams = new ParameterParser(array('accept-language' => ''));
         $this->assertSame(array(
-                           'short_name:default' => 'short_name:default',
                            'name:default' => 'name:default',
-                           'short_name' => 'short_name',
                            'name' => 'name',
                            'brand' => 'brand',
                            'official_name:default' => 'official_name:default',
+                           'short_name:default' => 'short_name:default',
                            'official_name' => 'official_name',
+                           'short_name' => 'short_name',
                            'ref' => 'ref',
                            'type' => 'type'
                           ), $oParams->getPreferredLanguages('default'));
 
         $oParams = new ParameterParser(array('accept-language' => 'de,en'));
         $this->assertSame(array(
-                           'short_name:de' => 'short_name:de',
                            'name:de' => 'name:de',
-                           'short_name:en' => 'short_name:en',
                            'name:en' => 'name:en',
-                           'short_name' => 'short_name',
                            'name' => 'name',
                            'brand' => 'brand',
                            'official_name:de' => 'official_name:de',
+                           'short_name:de' => 'short_name:de',
                            'official_name:en' => 'official_name:en',
+                           'short_name:en' => 'short_name:en',
                            'official_name' => 'official_name',
+                           'short_name' => 'short_name',
                            'ref' => 'ref',
                            'type' => 'type'
                           ), $oParams->getPreferredLanguages('default'));
 
         $oParams = new ParameterParser(array('accept-language' => 'fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3'));
         $this->assertSame(array(
-                           'short_name:fr-ca' => 'short_name:fr-ca',
                            'name:fr-ca' => 'name:fr-ca',
-                           'short_name:fr' => 'short_name:fr',
                            'name:fr' => 'name:fr',
-                           'short_name:en-ca' => 'short_name:en-ca',
                            'name:en-ca' => 'name:en-ca',
-                           'short_name:en' => 'short_name:en',
                            'name:en' => 'name:en',
-                           'short_name' => 'short_name',
                            'name' => 'name',
                            'brand' => 'brand',
                            'official_name:fr-ca' => 'official_name:fr-ca',
+                           'short_name:fr-ca' => 'short_name:fr-ca',
                            'official_name:fr' => 'official_name:fr',
+                           'short_name:fr' => 'short_name:fr',
                            'official_name:en-ca' => 'official_name:en-ca',
+                           'short_name:en-ca' => 'short_name:en-ca',
                            'official_name:en' => 'official_name:en',
+                           'short_name:en' => 'short_name:en',
                            'official_name' => 'official_name',
+                           'short_name' => 'short_name',
                            'ref' => 'ref',
                            'type' => 'type',
                           ), $oParams->getPreferredLanguages('default'));
 
         $oParams = new ParameterParser(array('accept-language' => 'ja_rm,zh_pinyin'));
         $this->assertSame(array(
-                           'short_name:ja_rm' => 'short_name:ja_rm',
                            'name:ja_rm' => 'name:ja_rm',
-                           'short_name:zh_pinyin' => 'short_name:zh_pinyin',
                            'name:zh_pinyin' => 'name:zh_pinyin',
-                           'short_name:ja' => 'short_name:ja',
                            'name:ja' => 'name:ja',
-                           'short_name:zh' => 'short_name:zh',
                            'name:zh' => 'name:zh',
-                           'short_name' => 'short_name',
                            'name' => 'name',
                            'brand' => 'brand',
                            'official_name:ja_rm' => 'official_name:ja_rm',
+                           'short_name:ja_rm' => 'short_name:ja_rm',
                            'official_name:zh_pinyin' => 'official_name:zh_pinyin',
+                           'short_name:zh_pinyin' => 'short_name:zh_pinyin',
                            'official_name:ja' => 'official_name:ja',
+                           'short_name:ja' => 'short_name:ja',
                            'official_name:zh' => 'official_name:zh',
+                           'short_name:zh' => 'short_name:zh',
                            'official_name' => 'official_name',
+                           'short_name' => 'short_name',
                            'ref' => 'ref',
                            'type' => 'type',
                           ), $oParams->getPreferredLanguages('default'));
index cb237be6d74cd7478e1842c37bdc327ecfe50997..9e6c9d76c757a38c70ba4a722207881c13368e98 100644 (file)
@@ -27,77 +27,127 @@ if ($aCMDResult['wiki-import']) {
     foreach (explode(',', $sLanguageIn) as $sLanguage) {
         $sURL = 'https://wiki.openstreetmap.org/wiki/Special:Export/Nominatim/Special_Phrases/'.strtoupper($sLanguage);
         $sWikiPageXML = file_get_contents($sURL);
-        if (preg_match_all('#\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([\\-YN])#', $sWikiPageXML, $aMatches, PREG_SET_ORDER)) {
-            foreach ($aMatches as $aMatch) {
-                $sLabel = trim($aMatch[1]);
-                if ($oNormalizer !== null) {
-                    $sTrans = pg_escape_string($oNormalizer->transliterate($sLabel));
-                } else {
-                    $sTrans = null;
-                }
-                $sClass = trim($aMatch[2]);
-                $sType = trim($aMatch[3]);
-                // hack around a bug where building=yes was imported with
-                // quotes into the wiki
-                $sType = preg_replace('/&quot;/', '', $sType);
-                // sanity check, in case somebody added garbage in the wiki
-                if (preg_match('/^\\w+$/', $sClass) < 1
-                    || preg_match('/^\\w+$/', $sType) < 1
-                ) {
-                    trigger_error("Bad class/type for language $sLanguage: $sClass=$sType");
-                    exit;
-                }
-                // blacklisting: disallow certain class/type combinations
-                if (isset($aTagsBlacklist[$sClass]) && in_array($sType, $aTagsBlacklist[$sClass])) {
-                    // fwrite(STDERR, "Blacklisted: ".$sClass."/".$sType."\n");
-                    continue;
-                }
-                // whitelisting: if class is in whitelist, allow only tags in the list
-                if (isset($aTagsWhitelist[$sClass]) && !in_array($sType, $aTagsWhitelist[$sClass])) {
-                    // fwrite(STDERR, "Non-Whitelisted: ".$sClass."/".$sType."\n");
-                    continue;
-                }
-                $aPairs[$sClass.'|'.$sType] = array($sClass, $sType);
-
-                switch (trim($aMatch[4])) {
-                    case 'near':
-                        echo "select getorcreate_amenityoperator(make_standard_name('".pg_escape_string($sLabel)."'), '$sTrans', '$sClass', '$sType', 'near');\n";
-                        break;
-                    case 'in':
-                        echo "select getorcreate_amenityoperator(make_standard_name('".pg_escape_string($sLabel)."'), '$sTrans', '$sClass', '$sType', 'in');\n";
-                        break;
-                    default:
-                        echo "select getorcreate_amenity(make_standard_name('".pg_escape_string($sLabel)."'), '$sTrans', '$sClass', '$sType');\n";
-                        break;
-                }
+
+        if (!preg_match_all(
+            '#\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([\\-YN])#',
+            $sWikiPageXML,
+            $aMatches,
+            PREG_SET_ORDER
+        )) {
+            continue;
+        }
+
+        foreach ($aMatches as $aMatch) {
+            $sLabel = trim($aMatch[1]);
+            if ($oNormalizer !== null) {
+                $sTrans = pg_escape_string($oNormalizer->transliterate($sLabel));
+            } else {
+                $sTrans = null;
+            }
+            $sClass = trim($aMatch[2]);
+            $sType = trim($aMatch[3]);
+            // hack around a bug where building=yes was imported with
+            // quotes into the wiki
+            $sType = preg_replace('/(&quot;|")/', '', $sType);
+            // sanity check, in case somebody added garbage in the wiki
+            if (preg_match('/^\\w+$/', $sClass) < 1
+                || preg_match('/^\\w+$/', $sType) < 1
+            ) {
+                trigger_error("Bad class/type for language $sLanguage: $sClass=$sType");
+                exit;
+            }
+            // blacklisting: disallow certain class/type combinations
+            if (isset($aTagsBlacklist[$sClass]) && in_array($sType, $aTagsBlacklist[$sClass])) {
+                // fwrite(STDERR, "Blacklisted: ".$sClass."/".$sType."\n");
+                continue;
+            }
+            // whitelisting: if class is in whitelist, allow only tags in the list
+            if (isset($aTagsWhitelist[$sClass]) && !in_array($sType, $aTagsWhitelist[$sClass])) {
+                // fwrite(STDERR, "Non-Whitelisted: ".$sClass."/".$sType."\n");
+                continue;
+            }
+            $aPairs[$sClass.'|'.$sType] = array($sClass, $sType);
+
+            switch (trim($aMatch[4])) {
+                case 'near':
+                    printf(
+                        "SELECT getorcreate_amenityoperator(make_standard_name('%s'), '%s', '%s', '%s', 'near');\n",
+                        pg_escape_string($sLabel),
+                        $sTrans,
+                        $sClass,
+                        $sType
+                    );
+                    break;
+                case 'in':
+                    printf(
+                        "SELECT getorcreate_amenityoperator(make_standard_name('%s'), '%s', '%s', '%s', 'in');\n",
+                        pg_escape_string($sLabel),
+                        $sTrans,
+                        $sClass,
+                        $sType
+                    );
+                    break;
+                default:
+                    printf(
+                        "SELECT getorcreate_amenity(make_standard_name('%s'), '%s', '%s', '%s');\n",
+                        pg_escape_string($sLabel),
+                        $sTrans,
+                        $sClass,
+                        $sType
+                    );
+                    break;
             }
         }
     }
 
-    echo 'create index idx_placex_classtype on placex (class, type);';
+    echo 'CREATE INDEX idx_placex_classtype ON placex (class, type);';
 
     foreach ($aPairs as $aPair) {
-        echo 'create table place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]);
-        if (CONST_Tablespace_Aux_Data)
-            echo ' tablespace '.CONST_Tablespace_Aux_Data;
-        echo ' as select place_id as place_id,st_centroid(geometry) as centroid from placex where ';
-        echo "class = '".pg_escape_string($aPair[0])."' and type = '".pg_escape_string($aPair[1])."'";
-        echo ";\n";
-
-        echo 'CREATE INDEX idx_place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).'_centroid ';
-        echo 'ON place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).' USING GIST (centroid)';
-        if (CONST_Tablespace_Aux_Index)
-            echo ' tablespace '.CONST_Tablespace_Aux_Index;
-        echo ";\n";
-
-        echo 'CREATE INDEX idx_place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).'_place_id ';
-        echo 'ON place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).' USING btree(place_id)';
-        if (CONST_Tablespace_Aux_Index)
-            echo ' tablespace '.CONST_Tablespace_Aux_Index;
-        echo ";\n";
-
-        echo 'GRANT SELECT ON place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).' TO "'.CONST_Database_Web_User."\";\n";
+        $sql_tablespace = CONST_Tablespace_Aux_Data ? ' TABLESPACE '.CONST_Tablespace_Aux_Data : '';
+
+        printf(
+            'CREATE TABLE place_classtype_%s_%s'
+            . $sql_tablespace
+            . ' AS'
+            . ' SELECT place_id AS place_id,st_centroid(geometry) AS centroid FROM placex'
+            . " WHERE class = '%s' AND type = '%s'"
+            . ";\n",
+            pg_escape_string($aPair[0]),
+            pg_escape_string($aPair[1]),
+            pg_escape_string($aPair[0]),
+            pg_escape_string($aPair[1])
+        );
+
+        printf(
+            'CREATE INDEX idx_place_classtype_%s_%s_centroid'
+            . ' ON place_classtype_%s_%s USING GIST (centroid)'
+            . $sql_tablespace
+            . ";\n",
+            pg_escape_string($aPair[0]),
+            pg_escape_string($aPair[1]),
+            pg_escape_string($aPair[0]),
+            pg_escape_string($aPair[1])
+        );
+
+        printf(
+            'CREATE INDEX idx_place_classtype_%s_%s_place_id'
+            . ' ON place_classtype_%s_%s USING btree(place_id)'
+            . $sql_tablespace
+            . ";\n",
+            pg_escape_string($aPair[0]),
+            pg_escape_string($aPair[1]),
+            pg_escape_string($aPair[0]),
+            pg_escape_string($aPair[1])
+        );
+
+        printf(
+            'GRANT SELECT ON place_classtype_%s_%s TO "%s"'
+            . ";\n",
+            pg_escape_string($aPair[0]),
+            pg_escape_string($aPair[1]),
+            CONST_Database_Web_User
+        );
     }
 
-    echo 'drop index idx_placex_classtype;';
+    echo 'DROP INDEX idx_placex_classtype;';
 }