]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge remote-tracking branch 'upstream/master'
authorSarah Hoffmann <lonvia@denofr.de>
Sun, 7 Jan 2024 14:24:30 +0000 (15:24 +0100)
committerSarah Hoffmann <lonvia@denofr.de>
Sun, 7 Jan 2024 14:24:30 +0000 (15:24 +0100)
nominatim/api/search/db_searches.py
nominatim/api/search/icu_tokenizer.py
nominatim/api/status.py
nominatim/tools/check_database.py
nominatim/tools/convert_sqlite.py
test/python/api/search/test_icu_query_analyzer.py
test/python/tools/test_check_database.py

index cc352134cffd313ab5dd846357021359c0fc8105..254d2ca6703e8f20c4056a694b8a15c4353e841a 100644 (file)
@@ -663,7 +663,7 @@ class PlaceSearch(AbstractSearch):
                 sql = sql.where(tsearch.c.centroid
                                          .intersects(VIEWBOX_PARAM,
                                                      use_index=details.viewbox.area < 0.2))
-            elif self.expected_count >= 10000:
+            elif not self.postcodes and not self.housenumbers and self.expected_count >= 10000:
                 sql = sql.where(tsearch.c.centroid
                                          .intersects(VIEWBOX2_PARAM,
                                                      use_index=details.viewbox.area < 0.5))
index ff1c3feed40069328d4fdc01aec77745356a70bf..6f3e09e88d2dc503ed0471c2eaa2f3c05f903562 100644 (file)
@@ -8,7 +8,6 @@
 Implementation of query analysis for the ICU tokenizer.
 """
 from typing import Tuple, Dict, List, Optional, NamedTuple, Iterator, Any, cast
-from copy import copy
 from collections import defaultdict
 import dataclasses
 import difflib
@@ -188,10 +187,6 @@ class ICUQueryAnalyzer(AbstractQueryAnalyzer):
                             query.add_token(trange, qmod.TokenType.NEAR_ITEM, token)
                     else:
                         query.add_token(trange, qmod.TokenType.QUALIFIER, token)
-                        if trange.start == 0 or trange.end == query.num_token_slots():
-                            token = copy(token)
-                            token.penalty += 0.1 * (query.num_token_slots())
-                            query.add_token(trange, qmod.TokenType.NEAR_ITEM, token)
                 else:
                     query.add_token(trange, DB_TO_TOKEN_TYPE[row.type], token)
 
index adccf7a55409ef240f040c83a87c2f112f73af1a..8ac92f35835d0914e1d069b4cfef276ff95ac8e6 100644 (file)
@@ -37,7 +37,10 @@ async def get_status(conn: SearchConnection) -> StatusResult:
     status.data_updated = await conn.scalar(sql)
 
     if status.data_updated is not None:
-        status.data_updated = status.data_updated.replace(tzinfo=dt.timezone.utc)
+        if status.data_updated.tzinfo is None:
+            status.data_updated = status.data_updated.replace(tzinfo=dt.timezone.utc)
+        else:
+            status.data_updated = status.data_updated.astimezone(dt.timezone.utc)
 
     # Database version
     try:
index b1cfce57b9f4531d80a4ee80b2aaa95cd6af21ff..721f2ceea0630b61ea18b9cb117e34f7577a9421 100644 (file)
@@ -13,9 +13,11 @@ from textwrap import dedent
 
 from nominatim.config import Configuration
 from nominatim.db.connection import connect, Connection
+from nominatim.db import properties
 from nominatim.errors import UsageError
 from nominatim.tokenizer import factory as tokenizer_factory
 from nominatim.tools import freeze
+from nominatim.version import NOMINATIM_VERSION, parse_version
 
 CHECKLIST = []
 
@@ -146,11 +148,52 @@ def check_connection(conn: Any, config: Configuration) -> CheckResult:
 
     return CheckState.OK
 
+@_check(hint="""\
+             Database version ({db_version}) doesn't match Nominatim version ({nom_version})
+
+             Hints:
+             * Are you connecting to the correct database?
+             
+             {instruction}
+
+             Check the Migration chapter of the Administration Guide.
+
+             Project directory: {config.project_dir}
+             Current setting of NOMINATIM_DATABASE_DSN: {config.DATABASE_DSN}
+             """)
+def check_database_version(conn: Connection, config: Configuration) -> CheckResult:
+    """ Checking database_version matches Nominatim software version
+    """
+
+    if conn.table_exists('nominatim_properties'):
+        db_version_str = properties.get_property(conn, 'database_version')
+    else:
+        db_version_str = None
+
+    if db_version_str is not None:
+        db_version = parse_version(db_version_str)
+
+        if db_version == NOMINATIM_VERSION:
+            return CheckState.OK
+
+        instruction = (
+            'Run migrations: nominatim admin --migrate'
+            if db_version < NOMINATIM_VERSION
+            else 'You need to upgrade the Nominatim software.'
+        )
+    else:
+        instruction = ''
+
+    return CheckState.FATAL, dict(db_version=db_version_str,
+                                  nom_version=NOMINATIM_VERSION,
+                                  instruction=instruction,
+                                  config=config)
+
 @_check(hint="""\
              placex table not found
 
              Hints:
-             * Are you connecting to the right database?
+             * Are you connecting to the correct database?
              * Did the import process finish without errors?
 
              Project directory: {config.project_dir}
index 3e5847107efbd5c10016e03316560581feff165b..1e7beae57645c172e15f72f999ce178a0ea4beeb 100644 (file)
@@ -7,13 +7,14 @@
 """
 Exporting a Nominatim database to SQlite.
 """
-from typing import Set
+from typing import Set, Any
+import datetime as dt
 import logging
 from pathlib import Path
 
 import sqlalchemy as sa
 
-from nominatim.typing import SaSelect
+from nominatim.typing import SaSelect, SaRow
 from nominatim.db.sqlalchemy_types import Geometry, IntArray
 from nominatim.api.search.query_analyzer_factory import make_query_analyzer
 import nominatim.api as napi
@@ -124,12 +125,20 @@ class SqliteWriter:
     async def copy_data(self) -> None:
         """ Copy data for all registered tables.
         """
+        def _getfield(row: SaRow, key: str) -> Any:
+            value = getattr(row, key)
+            if isinstance(value, dt.datetime):
+                if value.tzinfo is not None:
+                    value = value.astimezone(dt.timezone.utc)
+            return value
+
         for table in self.dest.t.meta.sorted_tables:
             LOG.warning("Copying '%s'", table.name)
             async_result = await self.src.connection.stream(self.select_from(table.name))
 
             async for partition in async_result.partitions(10000):
-                data = [{('class_' if k == 'class' else k): getattr(r, k) for k in r._fields}
+                data = [{('class_' if k == 'class' else k): _getfield(r, k)
+                         for k in r._fields}
                         for r in partition]
                 await self.dest.execute(table.insert(), data)
 
index a88ca8b82e4facc800aa23c507f309f57c4c8311..6a17e32abab37475d8ab5178d2a5ee5fc2fffe1e 100644 (file)
@@ -148,9 +148,9 @@ async def test_qualifier_words(conn):
     query = await ana.analyze_query(make_phrase('foo BAR foo BAR foo'))
 
     assert query.num_token_slots() == 5
-    assert set(t.ttype for t in query.nodes[0].starting) == {TokenType.NEAR_ITEM, TokenType.QUALIFIER}
+    assert set(t.ttype for t in query.nodes[0].starting) == {TokenType.QUALIFIER}
     assert set(t.ttype for t in query.nodes[2].starting) == {TokenType.QUALIFIER}
-    assert set(t.ttype for t in query.nodes[4].starting) == {TokenType.NEAR_ITEM, TokenType.QUALIFIER}
+    assert set(t.ttype for t in query.nodes[4].starting) == {TokenType.QUALIFIER}
 
 
 @pytest.mark.asyncio
index 4dd536b68daae4bf3bf9cea090f941afd5536e6f..65f0590320ad09a309b91ff7f693ddae1b2cebe5 100644 (file)
@@ -10,6 +10,7 @@ Tests for database integrity checks.
 import pytest
 
 from nominatim.tools import check_database as chkdb
+import nominatim.version
 
 def test_check_database_unknown_db(def_config, monkeypatch):
     monkeypatch.setenv('NOMINATIM_DATABASE_DSN', 'pgsql:dbname=fjgkhughwgh2423gsags')
@@ -20,15 +21,25 @@ def test_check_database_fatal_test(def_config, temp_db):
     assert chkdb.check_database(def_config) == 1
 
 
-def test_check_conection_good(temp_db_conn, def_config):
+def test_check_connection_good(temp_db_conn, def_config):
     assert chkdb.check_connection(temp_db_conn, def_config) == chkdb.CheckState.OK
 
 
-def test_check_conection_bad(def_config):
+def test_check_connection_bad(def_config):
     badconn = chkdb._BadConnection('Error')
     assert chkdb.check_connection(badconn, def_config) == chkdb.CheckState.FATAL
 
 
+def test_check_database_version_good(property_table, temp_db_conn, def_config):
+    property_table.set('database_version',
+                       '{0[0]}.{0[1]}.{0[2]}-{0[3]}'.format(nominatim.version.NOMINATIM_VERSION))
+    assert chkdb.check_database_version(temp_db_conn, def_config) == chkdb.CheckState.OK
+
+def test_check_database_version_bad(property_table, temp_db_conn, def_config):
+    property_table.set('database_version', '3.9.9-9')
+    assert chkdb.check_database_version(temp_db_conn, def_config) == chkdb.CheckState.FATAL
+
+
 def test_check_placex_table_good(table_factory, temp_db_conn, def_config):
     table_factory('placex')
     assert chkdb.check_placex_table(temp_db_conn, def_config) == chkdb.CheckState.OK