from typing import List, Tuple, Callable, Any
import logging
-from psycopg2 import sql as pysql
+from psycopg import sql as pysql
from ..errors import UsageError
from ..config import Configuration
from ..db import properties
-from ..db.connection import connect, Connection
+from ..db.connection import connect, Connection, server_version_tuple,\
+ table_has_column, table_exists, execute_scalar, register_hstore
from ..version import NominatimVersion, NOMINATIM_VERSION, parse_version
from ..tokenizer import factory as tokenizer_factory
from . import refresh
if necesssary.
"""
with connect(config.get_libpq_dsn()) as conn:
- if conn.table_exists('nominatim_properties'):
+ register_hstore(conn)
+ if table_exists(conn, 'nominatim_properties'):
db_version_str = properties.get_property(conn, 'database_version')
else:
db_version_str = None
Only migrations for 3.6 and later are supported, so bail out
when the version seems older.
"""
- with conn.cursor() as cur:
- # In version 3.6, the country_name table was updated. Check for that.
- cnt = cur.scalar("""SELECT count(*) FROM
- (SELECT svals(name) FROM country_name
- WHERE country_code = 'gb')x;
- """)
- if cnt < 100:
- LOG.fatal('It looks like your database was imported with a version '
- 'prior to 3.6.0. Automatic migration not possible.')
- raise UsageError('Migration not possible.')
+ # In version 3.6, the country_name table was updated. Check for that.
+ cnt = execute_scalar(conn, """SELECT count(*) FROM
+ (SELECT svals(name) FROM country_name
+ WHERE country_code = 'gb')x;
+ """)
+ if cnt < 100:
+ LOG.fatal('It looks like your database was imported with a version '
+ 'prior to 3.6.0. Automatic migration not possible.')
+ raise UsageError('Migration not possible.')
return NominatimVersion(3, 5, 0, 99)
def add_nominatim_property_table(conn: Connection, config: Configuration, **_: Any) -> None:
""" Add nominatim_property table.
"""
- if not conn.table_exists('nominatim_properties'):
+ if not table_exists(conn, 'nominatim_properties'):
with conn.cursor() as cur:
cur.execute(pysql.SQL("""CREATE TABLE nominatim_properties (
property TEXT,
configuration for the backwards-compatible legacy tokenizer
"""
if properties.get_property(conn, 'tokenizer') is None:
- with conn.cursor() as cur:
- for table in ('placex', 'location_property_osmline'):
- has_column = cur.scalar("""SELECT count(*) FROM information_schema.columns
- WHERE table_name = %s
- and column_name = 'token_info'""",
- (table, ))
- if has_column == 0:
+ for table in ('placex', 'location_property_osmline'):
+ if not table_has_column(conn, table, 'token_info'):
+ with conn.cursor() as cur:
cur.execute(pysql.SQL('ALTER TABLE {} ADD COLUMN token_info JSONB')
.format(pysql.Identifier(table)))
tokenizer = tokenizer_factory.create_tokenizer(config, init_db=False,
The inclusion is needed for efficient lookup of housenumbers in
full address searches.
"""
- if conn.server_version_tuple() >= (11, 0, 0):
+ if server_version_tuple(conn) >= (11, 0, 0):
with conn.cursor() as cur:
cur.execute(""" CREATE INDEX IF NOT EXISTS
idx_location_property_tiger_housenumber_migrated
Also converts the data into the stricter format which requires that
startnumbers comply with the odd/even requirements.
"""
- if conn.table_has_column('location_property_osmline', 'step'):
+ if table_has_column(conn, 'location_property_osmline', 'step'):
return
with conn.cursor() as cur:
def add_step_column_for_tiger(conn: Connection, **_: Any) -> None:
""" Add a new column 'step' to the tiger data table.
"""
- if conn.table_has_column('location_property_tiger', 'step'):
+ if table_has_column(conn, 'location_property_tiger', 'step'):
return
with conn.cursor() as cur:
""" Add a new column 'derived_name' which in the future takes the
country names as imported from OSM data.
"""
- if not conn.table_has_column('country_name', 'derived_name'):
+ if not table_has_column(conn, 'country_name', 'derived_name'):
with conn.cursor() as cur:
cur.execute("ALTER TABLE country_name ADD COLUMN derived_name public.HSTORE")
""" Names from the country table should be marked as internal to prevent
them from being deleted. Only necessary for ICU tokenizer.
"""
- import psycopg2.extras # pylint: disable=import-outside-toplevel
-
tokenizer = tokenizer_factory.get_tokenizer_for_db(config)
with tokenizer.name_analyzer() as analyzer:
with conn.cursor() as cur:
- psycopg2.extras.register_hstore(cur)
cur.execute("SELECT country_code, name FROM country_name")
for country_code, names in cur:
The table is only necessary when updates are possible, i.e.
the database is not in freeze mode.
"""
- if conn.table_exists('place'):
+ if table_exists(conn, 'place'):
with conn.cursor() as cur:
cur.execute("""CREATE TABLE IF NOT EXISTS place_to_be_deleted (
osm_type CHAR(1),
def split_pending_index(conn: Connection, **_: Any) -> None:
""" Reorganise indexes for pending updates.
"""
- if conn.table_exists('place'):
+ if table_exists(conn, 'place'):
with conn.cursor() as cur:
cur.execute("""CREATE INDEX IF NOT EXISTS idx_placex_rank_address_sector
ON placex USING BTREE (rank_address, geometry_sector)
def enable_forward_dependencies(conn: Connection, **_: Any) -> None:
""" Create indexes for updates with forward dependency tracking (long-running).
"""
- if conn.table_exists('planet_osm_ways'):
+ if table_exists(conn, 'planet_osm_ways'):
with conn.cursor() as cur:
cur.execute("""SELECT * FROM pg_indexes
WHERE tablename = 'planet_osm_ways'
def create_postcode_parent_index(conn: Connection, **_: Any) -> None:
""" Create index needed for updating postcodes when a parent changes.
"""
- if conn.table_exists('planet_osm_ways'):
+ if table_exists(conn, 'planet_osm_ways'):
with conn.cursor() as cur:
cur.execute("""CREATE INDEX IF NOT EXISTS
idx_location_postcode_parent_place_id