-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# This file is part of Nominatim.
-# Copyright (C) 2020 Sarah Hoffmann
-
-"""
-Script for analysing the indexing process.
-
-The script enables detailed logging for nested statements and then
-runs the indexing process for teh given object. Detailed 'EXPLAIN ANALYSE'
-information is printed for each executed query in the trigger. The
-transaction is then rolled back, so that no actual changes to the database
-happen. It also disables logging into the system log, so that the
-log files are not cluttered.
-"""
-
-from argparse import ArgumentParser, RawDescriptionHelpFormatter, ArgumentTypeError
-import psycopg2
-import getpass
-import re
-
-class Analyser(object):
-
- def __init__(self, options):
- password = None
- if options.password_prompt:
- password = getpass.getpass("Database password: ")
-
- self.options = options
- self.conn = psycopg2.connect(dbname=options.dbname,
- user=options.user,
- password=password,
- host=options.host,
- port=options.port)
-
-
-
- def run(self):
- c = self.conn.cursor()
-
- if self.options.placeid:
- place_id = self.options.placeid
- else:
- if self.options.rank:
- c.execute(f"""select place_id from placex
- where rank_address = {self.options.rank}
- and linked_place_id is null
- limit 1""")
- objinfo = f"rank {self.options.rank}"
-
- if self.options.osmid:
- osm_type = self.options.osmid[0].upper()
- if osm_type not in ('N', 'W', 'R'):
- raise RuntimeError("OSM ID must be of form <N|W|R><id>")
- try:
- osm_id = int(self.options.osmid[1:])
- except ValueError:
- raise RuntimeError("OSM ID must be of form <N|W|R><id>")
-
- c.execute(f"""SELECT place_id FROM placex
- WHERE osm_type = '{osm_type}' AND osm_id = {osm_id}""")
- objinfo = f"OSM object {self.options.osmid}"
-
-
- if c.rowcount < 1:
- raise RuntimeError(f"Cannot find a place for {objinfo}.")
- place_id = c.fetchone()[0]
-
- c.execute(f"""update placex set indexed_status = 2 where
- place_id = {place_id}""")
-
- c.execute("""SET auto_explain.log_min_duration = '0';
- SET auto_explain.log_analyze = 'true';
- SET auto_explain.log_nested_statements = 'true';
- LOAD 'auto_explain';
- SET client_min_messages = LOG;
- SET log_min_messages = FATAL""");
-
- c.execute(f"""update placex set indexed_status = 0 where
- place_id = {place_id}""")
-
- c.close() # automatic rollback
-
- for l in self.conn.notices:
- print(l)
-
-
-if __name__ == '__main__':
- def h(s):
- return re.sub("\s\s+" , " ", s)
-
- p = ArgumentParser(description=__doc__,
- formatter_class=RawDescriptionHelpFormatter)
-
- group = p.add_mutually_exclusive_group(required=True)
- group.add_argument('--rank', dest='rank', type=int,
- help='Analyse indexing of the given address rank')
- group.add_argument('--osm-id', dest='osmid', type=str,
- help='Analyse indexing of the given OSM object')
- group.add_argument('--place-id', dest='placeid', type=int,
- help='Analyse indexing of the given Nominatim object')
- p.add_argument('-d', '--database',
- dest='dbname', action='store', default='nominatim',
- help='Name of the PostgreSQL database to connect to.')
- p.add_argument('-U', '--username',
- dest='user', action='store',
- help='PostgreSQL user name.')
- p.add_argument('-W', '--password',
- dest='password_prompt', action='store_true',
- help='Force password prompt.')
- p.add_argument('-H', '--host',
- dest='host', action='store',
- help='PostgreSQL server hostname or socket location.')
- p.add_argument('-P', '--port',
- dest='port', action='store',
- help='PostgreSQL server port')
-
- Analyser(p.parse_args()).run()