{
"status": 0,
"message": "OK",
- "data_updated": "2020-05-04T14:47:00+00:00"
+ "data_updated": "2020-05-04T14:47:00+00:00",
+ "software_version": "3.6.0-0",
+ "database_version": "3.6.0-0"
}
```
+The `software_version` field contains the version of Nominatim used to serve
+the API. The `database_version` field contains the version of the data format
+in the database.
+
On error will also return HTTP status code 200 and a structure with error
code and message, e.g.
return $iDataDateEpoch;
}
+
+ public function databaseVersion()
+ {
+ $sSQL = 'SELECT value FROM nominatim_properties WHERE property = \'database_version\'';
+ return $this->oDB->getOne($sSQL);
+ }
}
protected $sIgnoreErrors;
protected $bEnableDiffUpdates;
protected $bEnableDebugStatements;
- protected $bNoPartitions;
protected $bDrop;
protected $oDB = null;
protected $oNominatimCmd;
} else {
$this->bEnableDebugStatements = false;
}
- if (isset($aCMDResult['no-partitions'])) {
- $this->bNoPartitions = $aCMDResult['no-partitions'];
- } else {
- $this->bNoPartitions = false;
- }
if (isset($aCMDResult['enable-diff-updates'])) {
$this->bEnableDiffUpdates = $aCMDResult['enable-diff-updates'];
} else {
private function pgsqlRunPartitionScript($sTemplate)
{
- $sSQL = 'select distinct partition from country_name';
+ $sSQL = 'select distinct partition from country_name order by partition';
$aPartitions = $this->db()->getCol($sSQL);
- if (!$this->bNoPartitions) $aPartitions[] = 0;
+ if ($aPartitions[0] != 0) $aPartitions[] = 0;
preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
foreach ($aMatches as $aMatch) {
$aResponse = array(
'status' => 0,
'message' => 'OK',
- 'data_updated' => (new DateTime('@'.$epoch))->format(DateTime::RFC3339)
+ 'data_updated' => (new DateTime('@'.$epoch))->format(DateTime::RFC3339),
+ 'software_version' => CONST_NominatimVersion
);
+ $sDatabaseVersion = $oStatus->databaseVersion();
+ if ($sDatabaseVersion) {
+ $aResponse['database_version'] = $sDatabaseVersion;
+ }
javascript_renderData($aResponse);
} else {
echo 'OK';
GRANT SELECT ON TABLE country_name TO "{www-user}";
+DROP TABLE IF EXISTS nominatim_properties;
+CREATE TABLE nominatim_properties (
+ property TEXT,
+ value TEXT
+);
+GRANT SELECT ON TABLE nominatim_properties TO "{www-user}";
+
drop table IF EXISTS word;
CREATE TABLE word (
word_id INTEGER,
from ..tools.exec_utils import run_legacy_script
from ..db.connection import connect
-from ..db import status
+from ..db import status, properties
+from ..version import NOMINATIM_VERSION
from ..errors import UsageError
# Do not repeat documentation of subcommand classes.
params = ['setup.php', '--create-tables', '--create-partition-tables']
if args.reverse_only:
params.append('--reverse-only')
- run_legacy_script(*params, nominatim_env=args)
+ run_legacy_script(*params, nominatim_env=args,
+ throw_on_fail=not args.ignore_errors)
LOG.warning('Create functions (2nd pass)')
with connect(args.config.get_libpq_dsn()) as conn:
args.threads or psutil.cpu_count() or 1)
LOG.warning('Calculate postcodes')
- run_legacy_script('setup.php', '--calculate-postcodes', nominatim_env=args)
+ run_legacy_script('setup.php', '--calculate-postcodes',
+ nominatim_env=args, throw_on_fail=not args.ignore_errors)
if args.continue_at is None or args.continue_at in ('load-data', 'indexing'):
LOG.warning('Indexing places')
params = ['setup.php', '--create-search-indices', '--create-country-names']
if args.no_updates:
params.append('--drop')
- run_legacy_script(*params, nominatim_env=args)
+ run_legacy_script(*params, nominatim_env=args, throw_on_fail=not args.ignore_errors)
webdir = args.project_dir / 'website'
LOG.warning('Setup website at %s', webdir)
except Exception as exc: # pylint: disable=broad-except
LOG.error('Cannot determine date of database: %s', exc)
+ properties.set_property(conn, 'database_version',
+ '{0[0]}.{0[1]}.{0[2]}-{0[3]}'.format(NOMINATIM_VERSION))
+
return 0
--- /dev/null
+"""
+Query and access functions for the in-database property table.
+"""
+
+def set_property(conn, name, value):
+ """ Add or replace the propery with the given name.
+ """
+ with conn.cursor() as cur:
+ cur.execute('SELECT value FROM nominatim_properties WHERE property = %s',
+ (name, ))
+
+ if cur.rowcount == 0:
+ sql = 'INSERT INTO nominatim_properties (value, property) VALUES (%s, %s)'
+ else:
+ sql = 'UPDATE nominatim_properties SET value = %s WHERE property = %s'
+
+ cur.execute(sql, (value, name))
+ conn.commit()
+
+def get_property(conn, name):
+ """ Return the current value of the given propery or None if the property
+ is not set.
+ """
+ with conn.cursor() as cur:
+ cur.execute('SELECT value FROM nominatim_properties WHERE property = %s',
+ (name, ))
+
+ return cur.fetchone()[0] if cur.rowcount > 0 else None
def get_url(url):
""" Get the contents from the given URL and return it as a UTF-8 string.
"""
- headers = {"User-Agent" : "Nominatim/" + NOMINATIM_VERSION}
+ headers = {"User-Agent" : "Nominatim/{0[0]}.{0[1]}.{0[2]}-{0[3]}".format(NOMINATIM_VERSION)}
try:
with urlrequest.urlopen(urlrequest.Request(url, headers=headers)) as response:
from psycopg2.extras import execute_values
from ..db.utils import execute_file
+from ..version import NOMINATIM_VERSION
LOG = logging.getLogger()
<?php
@define('CONST_Debug', $_GET['debug'] ?? false);
- @define('CONST_LibDir', '{}');
+ @define('CONST_LibDir', '{0}');
+ @define('CONST_NominatimVersion', '{1[0]}.{1[1]}.{1[2]}-{1[3]}');
- """.format(phplib_dir))
+ """.format(phplib_dir, NOMINATIM_VERSION))
for php_name, conf_name, var_type in PHP_CONST_DEFS:
if var_type == bool:
Version information for Nominatim.
"""
-NOMINATIM_VERSION = "3.6.0"
+# Version information: major, minor, patch level, database patch level
+#
+# The first three numbers refer to the last released version.
+#
+# The database patch level tracks important changes between releases
+# and must always be increased when there is a change to the database or code
+# that requires a migration.
+# Released versions always have a database patch level of 0.
+NOMINATIM_VERSION = (3, 6, 0, 0)
POSTGRESQL_REQUIRED_VERSION = (9, 3)
POSTGIS_REQUIRED_VERSION = (2, 2)
import pytest
+import nominatim.db.properties
import nominatim.cli
import nominatim.clicmd.api
import nominatim.clicmd.refresh
mock_func_factory(nominatim.tools.database_import, 'load_data'),
mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_full'),
mock_func_factory(nominatim.tools.refresh, 'setup_website'),
+ mock_func_factory(nominatim.db.properties, 'set_property')
]
cf_mock = mock_func_factory(nominatim.tools.refresh, 'create_functions')
cur.scalar('SELECT * FROM pg_tables')
+def test_cursor_scalar_no_rows(db, table_factory):
+ table_factory('dummy')
+
+ with db.cursor() as cur:
+ with pytest.raises(RuntimeError):
+ cur.scalar('SELECT id FROM dummy')
+
+
def test_get_pg_env_add_variable(monkeypatch):
monkeypatch.delenv('PGPASSWORD', raising=False)
env = get_pg_env('user=fooF')
--- /dev/null
+"""
+Tests for property table manpulation.
+"""
+import pytest
+
+from nominatim.db import properties
+
+@pytest.fixture
+def prop_table(table_factory):
+ table_factory('nominatim_properties', 'property TEXT, value TEXT')
+
+
+def test_get_property_existing(prop_table, temp_db_conn, temp_db_cursor):
+ temp_db_cursor.execute("INSERT INTO nominatim_properties VALUES('foo', 'bar')")
+
+ assert properties.get_property(temp_db_conn, 'foo') == 'bar'
+
+
+def test_get_property_unknown(prop_table, temp_db_conn, temp_db_cursor):
+ temp_db_cursor.execute("INSERT INTO nominatim_properties VALUES('other', 'bar')")
+
+ assert properties.get_property(temp_db_conn, 'foo') is None
+
+
+@pytest.mark.parametrize("prefill", (True, False))
+def test_set_property_new(prop_table, temp_db_conn, temp_db_cursor, prefill):
+ if prefill:
+ temp_db_cursor.execute("INSERT INTO nominatim_properties VALUES('something', 'bar')")
+
+ properties.set_property(temp_db_conn, 'something', 'else')
+
+ assert temp_db_cursor.scalar("""SELECT value FROM nominatim_properties
+ WHERE property = 'something'""") == 'else'
+
+ assert properties.get_property(temp_db_conn, 'something') == 'else'