env:
- TEST_SUITE=tests
- TEST_SUITE=monaco
+before_install:
+ - phpenv global 7.1
install:
- vagrant/install-on-travis-ci.sh
before_script:
- cd $TRAVIS_BUILD_DIR/
- if [[ $TEST_SUITE == "tests" ]]; then phpcs --report-width=120 . ; fi
- cd $TRAVIS_BUILD_DIR/test/php
- - if [[ $TEST_SUITE == "tests" ]]; then phpunit ./ ; fi
+ - if [[ $TEST_SUITE == "tests" ]]; then /usr/bin/phpunit ./ ; fi
- cd $TRAVIS_BUILD_DIR/test/bdd
- # behave --format=progress3 api
- if [[ $TEST_SUITE == "tests" ]]; then behave -DREMOVE_TEMPLATE=1 --format=progress3 db ; fi
filesystem does not fully support 'mmap'. A notable candidate is virtualbox's
vboxfs.
+### nominatim UPDATE failed: ERROR: buffer 179261 is not owned by resource owner Portal
+
+Several users [reported this](https://github.com/openstreetmap/Nominatim/issues/1168) during the initial import of the database. It's
+something Postgresql internal Nominatim doesn't control. And Postgresql forums
+suggest it's threading related but definitely some kind of crash of a process.
+Users reported either rebooting the server, different hardware or just trying
+the import again worked.
+
### The website shows: "Could not get word tokens"
The server cannot access your database. Add `&debug=1` to your URL
### "must be an array or an object that implements Countable" warning in /usr/share/pear/DB.php
-As reported starting PHP 7.2. This external DB library is no longer maintained and will be replaced in future Nominatim versions. In the meantime you'd have to manually change the line near 774 from
-`if (!count($dsn)) {` to `if (!$dsn && !count($dsn))`. [More details](https://github.com/openstreetmap/Nominatim/issues/1184)
-
-
-
+The warning started with PHP 7.2. Make sure you have at least [version 1.9.3 of PEAR DB](https://github.com/pear/DB/releases)
+installed.
### Website reports "DB Error: insufficient permissions"
private static function isAddress($aLine)
{
- return $aLine['isaddress'] == 't' || $aLine['type'] == 'country_code';
+ return $aLine['isaddress'] || $aLine['type'] == 'country_code';
}
public function getAddressDetails($bAll = false)
$sPrevResult = '';
foreach ($this->aAddressLines as $aLine) {
- if ($aLine['isaddress'] == 't' && $sPrevResult != $aLine['localname']) {
+ if ($aLine['isaddress'] && $sPrevResult != $aLine['localname']) {
$sPrevResult = $aLine['localname'];
$aParts[] = $sPrevResult;
}
public function getRow($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
try {
- if (isset($aInputVars)) {
- $stmt = $this->connection->prepare($sSQL);
- $stmt->execute($aInputVars);
- } else {
- $stmt = $this->connection->query($sSQL);
- }
+ $stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
$row = $stmt->fetch();
} catch (\PDOException $e) {
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
public function getOne($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
try {
- if (isset($aInputVars)) {
- $stmt = $this->connection->prepare($sSQL);
- $stmt->execute($aInputVars);
- } else {
- $stmt = $this->connection->query($sSQL);
- }
+ $stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
$row = $stmt->fetch(\PDO::FETCH_NUM);
if ($row === false) return false;
} catch (\PDOException $e) {
public function getAll($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
try {
- if (isset($aInputVars)) {
- $stmt = $this->connection->prepare($sSQL);
- $stmt->execute($aInputVars);
- } else {
- $stmt = $this->connection->query($sSQL);
- }
+ $stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
$rows = $stmt->fetchAll();
} catch (\PDOException $e) {
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
{
$aVals = array();
try {
- if (isset($aInputVars)) {
- $stmt = $this->connection->prepare($sSQL);
- $stmt->execute($aInputVars);
- } else {
- $stmt = $this->connection->query($sSQL);
- }
+ $stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
+
while ($val = $stmt->fetchColumn(0)) { // returns first column or false
$aVals[] = $val;
}
public function getAssoc($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
try {
- if (isset($aInputVars)) {
- $stmt = $this->connection->prepare($sSQL);
- $stmt->execute($aInputVars);
- } else {
- $stmt = $this->connection->query($sSQL);
- }
+ $stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
+
$aList = array();
while ($aRow = $stmt->fetch(\PDO::FETCH_NUM)) {
$aList[$aRow[0]] = $aRow[1];
return $aList;
}
+ /**
+ * Executes query. Returns a PDO statement to iterate over.
+ *
+ * @param string $sSQL
+ *
+ * @return PDOStatement
+ */
+ public function getQueryStatement($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
+ {
+ try {
+ if (isset($aInputVars)) {
+ $stmt = $this->connection->prepare($sSQL);
+ $stmt->execute($aInputVars);
+ } else {
+ $stmt = $this->connection->query($sSQL);
+ }
+ } catch (\PDOException $e) {
+ throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
+ }
+ return $stmt;
+ }
/**
* St. John's Way => 'St. John\'s Way'
return 'ARRAY['.join(',', $a).']';
}
- public function getLastError()
- {
- // https://secure.php.net/manual/en/pdo.errorinfo.php
- return $this->connection->errorInfo();
- }
-
/**
* Check if a table exists in the database. Returns true if it does.
*
13 => 18,
14 => 22, // Suburb
15 => 22,
- 16 => 26, // Street, TODO: major street?
- 17 => 26,
+ 16 => 26, // major street
+ 17 => 27, // minor street
18 => 30, // or >, Building
19 => 30, // or >, Building
);
$sSQL .= ' placex';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')';
$sSQL .= ' AND';
- // only streets
- if ($iMaxRank == 26) {
- $sSQL .= ' rank_address = 26';
- } else {
- $sSQL .= ' rank_address between 26 and '.$iMaxRank;
- }
+ $sSQL .= ' rank_address between 26 and '.$iMaxRank;
$sSQL .= ' and (name is not null or housenumber is not null';
$sSQL .= ' or rank_address between 26 and 27)';
$sSQL .= ' and (rank_address between 26 and 27';
// radius ?
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, 0.001)';
$sSQL .= ' AND parent_place_id = '.$iPlaceID;
- $sSQL .= ' and rank_address != 28';
+ $sSQL .= ' and rank_address > 28';
$sSQL .= ' and ST_GeometryType(geometry) != \'ST_LineString\'';
$sSQL .= ' and (name is not null or housenumber is not null)';
$sSQL .= ' and class not in (\'boundary\')';
$sSQL .= "p.postcode = '".reset($this->aName)."'";
$sSQL .= $this->countryCodeSQL(' AND p.country_code');
+ if ($this->oContext->bViewboxBounded) {
+ $sSQL .= ' AND ST_Intersects('.$this->oContext->sqlViewboxSmall.', geometry)';
+ }
$sSQL .= $this->oContext->excludeSQL(' AND p.place_id');
$sSQL .= " LIMIT $iLimit";
}
// Try accessing the C module, so we know early if something is wrong
- if (!checkModulePresence()) {
- fail('error loading nominatim.so module');
- }
+ checkModulePresence(); // raises exception on failure
if (!file_exists(CONST_ExtraDataPath.'/country_osm_grid.sql.gz')) {
echo 'Error: you need to download the country_osm_grid first:';
{
info('Create Functions');
- // Try accessing the C module, so we know eif something is wrong
- // update.php calls this function
- if (!checkModulePresence()) {
- fail('error loading nominatim.so module');
- }
+ // Try accessing the C module, so we know early if something is wrong
+ checkModulePresence(); // raises exception on failure
+
$this->createSqlFunctions();
}
function checkModulePresence()
{
- // Try accessing the C module, so we know early if something is wrong
- // and can simply error out.
+ // Try accessing the C module, so we know early if something is wrong.
+ // Raises Nominatim\DatabaseError on failure
+
$sModulePath = CONST_Database_Module_Path;
$sSQL = "CREATE FUNCTION nominatim_test_import_func(text) RETURNS text AS '";
$sSQL .= $sModulePath . "/nominatim.so', 'transliteration' LANGUAGE c IMMUTABLE STRICT";
$oDB = new \Nominatim\DB();
$oDB->connect();
-
- $bResult = true;
- try {
- $oDB->exec($sSQL);
- } catch (\Nominatim\DatabaseError $e) {
- echo "\nERROR: Failed to load nominatim module. Reason:\n";
- echo $oDB->getLastError()[2] . "\n\n";
- $bResult = false;
- }
-
- return $bResult;
+ $oDB->exec($sSQL, null, 'Database server failed to load '.$sModulePath.'/nominatim.so module');
}
function _one_row($aAddressLine){
- $bNotUsed = (isset($aAddressLine['isaddress']) && $aAddressLine['isaddress'] == 'f');
+ $bNotUsed = isset($aAddressLine['isaddress']) && !$aAddressLine['isaddress'];
echo '<tr class="' . ($bNotUsed?'notused':'') . '">'."\n";
echo ' <td class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>')."</td>\n";
if ($aPointDetails['calculated_importance']) {
kv('Importance' , $aPointDetails['calculated_importance'].($aPointDetails['importance']?'':' (estimated)') );
}
- kv('Coverage' , ($aPointDetails['isarea']=='t'?'Polygon':'Point') );
+ kv('Coverage' , ($aPointDetails['isarea']?'Polygon':'Point') );
kv('Centre Point' , $aPointDetails['lat'].','.$aPointDetails['lon'] );
kv('OSM' , osmLink($aPointDetails) );
if ($aPointDetails['wikipedia'])
$aPlaceDetails['rank_address'] = (int) $aPointDetails['rank_address'];
$aPlaceDetails['rank_search'] = (int) $aPointDetails['rank_search'];
-$aPlaceDetails['isarea'] = ($aPointDetails['isarea'] == 't');
+$aPlaceDetails['isarea'] = $aPointDetails['isarea'];
$aPlaceDetails['centroid'] = array(
'type' => 'Point',
'coordinates' => array( (float) $aPointDetails['lon'], (float) $aPointDetails['lat'] )
searchhousename HSTORE;
searchrankaddress INTEGER;
searchpostcode TEXT;
+ postcode_isaddress BOOL;
searchclass TEXT;
searchtype TEXT;
countryname HSTORE;
-- The place ein question might not have a direct entry in place_addressline.
-- Look for the parent of such places then and save if in for_place_id.
+ postcode_isaddress := true;
+
-- first query osmline (interpolation lines)
IF in_housenumber >= 0 THEN
SELECT parent_place_id, country_code, in_housenumber::text, 30, postcode,
searchcountrycode := location.country_code;
END IF;
IF location.type in ('postcode', 'postal_code') THEN
- location.isaddress := FALSE;
+ postcode_isaddress := false;
+ IF location.osm_type != 'R' THEN
+ location.isaddress := FALSE;
+ END IF;
END IF;
countrylocation := ROW(location.place_id, location.osm_type, location.osm_id,
location.name, location.class, location.type,
IF searchpostcode IS NOT NULL THEN
location := ROW(null, null, null, hstore('ref', searchpostcode), 'place',
- 'postcode', null, true, true, 5, 0)::addressline;
+ 'postcode', null, false, postcode_isaddress, 5, 0)::addressline;
RETURN NEXT location;
END IF;
| country_code |
| li |
+ Scenario: Postcode search with bounded viewbox restriction
+ When sending json search query "9486" with address
+ | bounded | viewbox |
+ | 1 | 9.55,47.20,9.58,47.22 |
+ Then result addresses contain
+ | postcode |
+ | 9486 |
+ When sending json search query "9486" with address
+ | bounded | viewbox |
+ | 1 | 5.00,20.00,6.00,21.00 |
+ Then exactly 0 results are returned
+
Scenario: Postcode search with structured query
When sending json search query "" with address
| postalcode | country |
$sOsmId = $aCMDResult['restrict-to-osm-relation'];
}
if ($sOsmType) {
- $sSQL = 'select place_id from placex where';
- $sSQL .= ' osm_type = '.$oDB->getDBQuoted($sOsmType);
- $sSQL .= ' and osm_id = '.$sOsmId;
- $sParentId = $oDB->getOne($sSQL);
+ $sSQL = 'select place_id from placex where osm_type = :osm_type and osm_id = :osm_id';
+ $sParentId = $oDB->getOne($sSQL, array('osm_type' => $sOsmType, 'osm_id' => $sOsmId));
if (!$sParentId) fail('Could not find place '.$sOsmType.' '.$sOsmId);
}
if ($sParentId) {
// Iterate over placeids
// to get further hierarchical information
//var_dump($sPlacexSQL);
- $aRes =& $oDB->query($sPlacexSQL);
+ $oResults = $oDB->getQueryStatement($sPlacexSQL);
$fOutstream = fopen('php://output', 'w');
- while ($aRes->fetchInto($aRow)) {
- //var_dump($aRow);
+ while ($aRow = $oResults->fetch()) {
+ //var_dump($aRow);
$iPlaceID = $aRow['place_id'];
- $sSQL = "select rank_address,get_name_by_language(name,$sLanguagePrefArraySQL) as localname from get_addressdata($iPlaceID, -1)";
+ $sSQL = "select rank_address,get_name_by_language(name,$sLanguagePrefArraySQL) as localname from get_addressdata(:place_id, -1)";
$sSQL .= ' WHERE isaddress';
$sSQL .= ' order by rank_address desc,isaddress desc';
- $aAddressLines = $oDB->getAll($sSQL);
+ $aAddressLines = $oDB->getAll($sSQL, array('place_id' => $iPlaceID));
$aOutput = array_fill(0, $iNumCol, '');
// output address parts
$sSQL = 'select array_agg(px.postcode) from placex px join place_addressline pa ';
$sSQL .= 'on px.place_id = pa.address_place_id ';
$sSQL .= 'where pa.cached_rank_address in (5,11) ';
- $sSQL .= 'and pa.place_id in (select place_id from place_addressline where address_place_id in ('.substr($aRow['place_ids'], 1, -1).')) ';
+ $sSQL .= 'and pa.place_id in (select place_id from place_addressline where address_place_id in (:first_place_id)) ';
$sSQL .= 'group by postcode order by count(*) desc limit 1';
- $sRes = $oDB->getOne($sSQL);
+ $sRes = $oDB->getOne($sSQL, array('first_place_id' => substr($aRow['place_ids'], 1, -1)));
$aOutput[$aColumnMapping['postcode']] = substr($sRes, 1, -1);
} else {
}
// Try accessing the C module, so we know early if something is wrong
-if (!checkModulePresence()) {
- fail('error loading nominatim.so module');
-}
+checkModulePresence(); // raises exception on failure
if ($aCMDResult['import-data'] || $aCMDResult['all']) {
$bDidSomething = true;
$sBatchEnd = $aLastState['lastimportdate'];
$iEndSequence = $aLastState['sequence_id'];
- if ($aLastState['indexed'] == 't') {
+ if ($aLastState['indexed']) {
// Sleep if the update interval has not yet been reached.
$fNextUpdate = $aLastState['unix_ts'] + CONST_Replication_Update_Interval;
if ($fNextUpdate > $fStartTime) {
composer global require "squizlabs/php_codesniffer=*"
sudo ln -s /home/travis/.config/composer/vendor/bin/phpcs /usr/bin/
+composer global require "phpunit/phpunit=7.*"
+sudo ln -s /home/travis/.config/composer/vendor/bin/phpunit /usr/bin/
+
sudo -u postgres createuser -S www-data
# Make sure that system servers can read from the home directory:
echo '<div class="line">';
echo '<span class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>').'</span>';
echo ' (';
- echo '<span class="area">'.($aAddressLine['isarea']=='t'?'Polygon':'Point').'</span>';
+ echo '<span class="area">'.($aAddressLine['isarea']?'Polygon':'Point').'</span>';
if ($sOSMType) echo ', <span class="osm"><span class="label"></span>'.$sOSMType.' '.osmLink($aAddressLine).'</span>';
echo ', <a href="hierarchy.php?place_id='.$aAddressLine['place_id'].'">GOTO</a>';
echo ', '.$aAddressLine['area'];