mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-16 15:47:58 +00:00
Nominatim::DB support input variables, custom error messages
This commit is contained in:
@@ -26,7 +26,7 @@ class AddressDetails
|
||||
$sSQL .= ' FROM get_addressdata('.$iPlaceID.','.$sHousenumber.')';
|
||||
$sSQL .= ' ORDER BY rank_address DESC, isaddress DESC';
|
||||
|
||||
$this->aAddressLines = chksql($oDB->getAll($sSQL));
|
||||
$this->aAddressLines = $oDB->getAll($sSQL);
|
||||
}
|
||||
|
||||
private static function isAddress($aLine)
|
||||
|
||||
307
lib/DB.php
Normal file
307
lib/DB.php
Normal file
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
require_once(CONST_BasePath.'/lib/DatabaseError.php');
|
||||
|
||||
/**
|
||||
* Uses PDO to access the database specified in the CONST_Database_DSN
|
||||
* setting.
|
||||
*/
|
||||
class DB
|
||||
{
|
||||
protected $connection;
|
||||
|
||||
public function __construct($sDSN = CONST_Database_DSN)
|
||||
{
|
||||
$this->sDSN = $sDSN;
|
||||
}
|
||||
|
||||
public function connect($bNew = false, $bPersistent = true)
|
||||
{
|
||||
if (isset($this->connection) && !$bNew) {
|
||||
return true;
|
||||
}
|
||||
$aConnOptions = array(
|
||||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
||||
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
|
||||
\PDO::ATTR_PERSISTENT => $bPersistent
|
||||
);
|
||||
|
||||
// https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php
|
||||
try {
|
||||
$conn = new \PDO($this->sDSN, null, null, $aConnOptions);
|
||||
} catch (\PDOException $e) {
|
||||
$sMsg = 'Failed to establish database connection:' . $e->getMessage();
|
||||
throw new \Nominatim\DatabaseError($sMsg, 500, null, $e->getMessage());
|
||||
}
|
||||
|
||||
$conn->exec("SET DateStyle TO 'sql,european'");
|
||||
$conn->exec("SET client_encoding TO 'utf-8'");
|
||||
$iMaxExecution = ini_get('max_execution_time');
|
||||
if ($iMaxExecution > 0) $conn->setAttribute(\PDO::ATTR_TIMEOUT, $iMaxExecution); // seconds
|
||||
|
||||
$this->connection = $conn;
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns the number of rows that were modified or deleted by the SQL
|
||||
// statement. If no rows were affected returns 0.
|
||||
public function exec($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
|
||||
{
|
||||
$val = null;
|
||||
try {
|
||||
if (isset($aInputVars)) {
|
||||
$stmt = $this->connection->prepare($sSQL);
|
||||
$stmt->execute($aInputVars);
|
||||
} else {
|
||||
$val = $this->connection->exec($sSQL);
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
$sErrMessage = $e->message();
|
||||
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes query. Returns first row as array.
|
||||
* Returns false if no result found.
|
||||
*
|
||||
* @param string $sSQL
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
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);
|
||||
}
|
||||
$row = $stmt->fetch();
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes query. Returns first value of first result.
|
||||
* Returns false if no results found.
|
||||
*
|
||||
* @param string $sSQL
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
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);
|
||||
}
|
||||
$row = $stmt->fetch(\PDO::FETCH_NUM);
|
||||
if ($row === false) return false;
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
|
||||
}
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes query. Returns array of results (arrays).
|
||||
* Returns empty array if no results found.
|
||||
*
|
||||
* @param string $sSQL
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
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);
|
||||
}
|
||||
$rows = $stmt->fetchAll();
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes query. Returns array of the first value of each result.
|
||||
* Returns empty array if no results found.
|
||||
*
|
||||
* @param string $sSQL
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function getCol($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
|
||||
{
|
||||
$aVals = array();
|
||||
try {
|
||||
if (isset($aInputVars)) {
|
||||
$stmt = $this->connection->prepare($sSQL);
|
||||
$stmt->execute($aInputVars);
|
||||
} else {
|
||||
$stmt = $this->connection->query($sSQL);
|
||||
}
|
||||
while ($val = $stmt->fetchColumn(0)) { // returns first column or false
|
||||
$aVals[] = $val;
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
|
||||
}
|
||||
return $aVals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes query. Returns associate array mapping first value to second value of each result.
|
||||
* Returns empty array if no results found.
|
||||
*
|
||||
* @param string $sSQL
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
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);
|
||||
}
|
||||
$aList = array();
|
||||
while ($aRow = $stmt->fetch(\PDO::FETCH_NUM)) {
|
||||
$aList[$aRow[0]] = $aRow[1];
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
|
||||
}
|
||||
return $aList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* St. John's Way => 'St. John\'s Way'
|
||||
*
|
||||
* @param string $sVal Text to be quoted.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDBQuoted($sVal)
|
||||
{
|
||||
return $this->connection->quote($sVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like getDBQuoted, but takes an array.
|
||||
*
|
||||
* @param array $aVals List of text to be quoted.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function getDBQuotedList($aVals)
|
||||
{
|
||||
return array_map(function ($sVal) {
|
||||
return $this->getDBQuoted($sVal);
|
||||
}, $aVals);
|
||||
}
|
||||
|
||||
/**
|
||||
* [1,2,'b'] => 'ARRAY[1,2,'b']''
|
||||
*
|
||||
* @param array $aVals List of text to be quoted.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getArraySQL($a)
|
||||
{
|
||||
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.
|
||||
*
|
||||
* @param string $sTableName
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function tableExists($sTableName)
|
||||
{
|
||||
$sSQL = 'SELECT count(*) FROM pg_tables WHERE tablename = :tablename';
|
||||
return ($this->getOne($sSQL, array(':tablename' => $sTableName)) == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since the DSN includes the database name, checks if the connection works.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function databaseExists()
|
||||
{
|
||||
$bExists = true;
|
||||
try {
|
||||
$this->connect(true);
|
||||
} catch (\Nominatim\DatabaseError $e) {
|
||||
$bExists = false;
|
||||
}
|
||||
return $bExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* e.g. 9.6, 10, 11.2
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getPostgresVersion()
|
||||
{
|
||||
$sVersionString = $this->getOne('SHOW server_version_num');
|
||||
preg_match('#([0-9]?[0-9])([0-9][0-9])[0-9][0-9]#', $sVersionString, $aMatches);
|
||||
return (float) ($aMatches[1].'.'.$aMatches[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* e.g. 2, 2.2
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getPostgisVersion()
|
||||
{
|
||||
$sVersionString = $this->getOne('select postgis_lib_version()');
|
||||
preg_match('#^([0-9]+)[.]([0-9]+)[.]#', $sVersionString, $aMatches);
|
||||
return (float) ($aMatches[1].'.'.$aMatches[2]);
|
||||
}
|
||||
|
||||
public static function parseDSN($sDSN)
|
||||
{
|
||||
// https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php
|
||||
$aInfo = array();
|
||||
if (preg_match('/^pgsql:(.+)/', $sDSN, $aMatches)) {
|
||||
foreach (explode(';', $aMatches[1]) as $sKeyVal) {
|
||||
list($sKey, $sVal) = explode('=', $sKeyVal, 2);
|
||||
if ($sKey == 'host') $sKey = 'hostspec';
|
||||
if ($sKey == 'dbname') $sKey = 'database';
|
||||
if ($sKey == 'user') $sKey = 'username';
|
||||
$aInfo[$sKey] = $sVal;
|
||||
}
|
||||
}
|
||||
return $aInfo;
|
||||
}
|
||||
}
|
||||
@@ -581,8 +581,9 @@ class Geocode
|
||||
|
||||
if ($sSpecialTerm && !$aSearches[0]->hasOperator()) {
|
||||
$sSpecialTerm = pg_escape_string($sSpecialTerm);
|
||||
$sToken = chksql(
|
||||
$this->oDB->getOne("SELECT make_standard_name('$sSpecialTerm')"),
|
||||
$sToken = $this->oDB->getOne(
|
||||
'SELECT make_standard_name(:term)',
|
||||
array(':term' => $sSpecialTerm),
|
||||
'Cannot decode query. Wrong encoding?'
|
||||
);
|
||||
$sSQL = 'SELECT class, type FROM word ';
|
||||
@@ -590,7 +591,7 @@ class Geocode
|
||||
$sSQL .= ' AND class is not null AND class not in (\'place\')';
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
$aSearchWords = chksql($this->oDB->getAll($sSQL));
|
||||
$aSearchWords = $this->oDB->getAll($sSQL);
|
||||
$aNewSearches = array();
|
||||
foreach ($aSearches as $oSearch) {
|
||||
foreach ($aSearchWords as $aSearchTerm) {
|
||||
@@ -628,8 +629,9 @@ class Geocode
|
||||
$aTokens = array();
|
||||
$aPhrases = array();
|
||||
foreach ($aInPhrases as $iPhrase => $sPhrase) {
|
||||
$sPhrase = chksql(
|
||||
$this->oDB->getOne('SELECT make_standard_name('.$this->oDB->getDBQuoted($sPhrase).')'),
|
||||
$sPhrase = $this->oDB->getOne(
|
||||
'SELECT make_standard_name(:phrase)',
|
||||
array(':phrase' => $sPhrase),
|
||||
'Cannot normalize query string (is it a UTF-8 string?)'
|
||||
);
|
||||
if (trim($sPhrase)) {
|
||||
@@ -830,7 +832,7 @@ class Geocode
|
||||
if ($aFilterSql) {
|
||||
$sSQL = join(' UNION ', $aFilterSql);
|
||||
Debug::printSQL($sSQL);
|
||||
$aFilteredIDs = chksql($this->oDB->getCol($sSQL));
|
||||
$aFilteredIDs = $this->oDB->getCol($sSQL);
|
||||
}
|
||||
|
||||
$tempIDs = array();
|
||||
|
||||
@@ -163,8 +163,8 @@ class PlaceLookup
|
||||
|
||||
public function lookupOSMID($sType, $iID)
|
||||
{
|
||||
$sSQL = "select place_id from placex where osm_type = '".$sType."' and osm_id = ".$iID;
|
||||
$iPlaceID = chksql($this->oDB->getOne($sSQL));
|
||||
$sSQL = 'select place_id from placex where osm_type = :type and osm_id = :id';
|
||||
$iPlaceID = $this->oDB->getOne($sSQL, array(':type' => $sType, ':id' => $iID));
|
||||
|
||||
if (!$iPlaceID) {
|
||||
return null;
|
||||
@@ -425,7 +425,7 @@ class PlaceLookup
|
||||
|
||||
$sSQL = join(' UNION ', $aSubSelects);
|
||||
Debug::printSQL($sSQL);
|
||||
$aPlaces = chksql($this->oDB->getAll($sSQL), 'Could not lookup place');
|
||||
$aPlaces = $this->oDB->getAll($sSQL, null, 'Could not lookup place');
|
||||
|
||||
foreach ($aPlaces as &$aPlace) {
|
||||
if ($this->bAddressDetails) {
|
||||
@@ -514,7 +514,7 @@ class PlaceLookup
|
||||
$sSQL .= $sFrom;
|
||||
}
|
||||
|
||||
$aPointPolygon = chksql($this->oDB->getRow($sSQL), 'Could not get outline');
|
||||
$aPointPolygon = $this->oDB->getRow($sSQL, null, 'Could not get outline');
|
||||
|
||||
if ($aPointPolygon && $aPointPolygon['place_id']) {
|
||||
if ($aPointPolygon['centrelon'] !== null && $aPointPolygon['centrelat'] !== null) {
|
||||
|
||||
@@ -63,8 +63,9 @@ class ReverseGeocode
|
||||
$sSQL .= ' and indexed_status = 0 and startnumber is not NULL ';
|
||||
$sSQL .= ' ORDER BY distance ASC limit 1';
|
||||
|
||||
return chksql(
|
||||
$this->oDB->getRow($sSQL),
|
||||
return $this->oDB->getRow(
|
||||
$sSQL,
|
||||
null,
|
||||
'Could not determine closest housenumber on an osm interpolation line.'
|
||||
);
|
||||
}
|
||||
@@ -92,8 +93,9 @@ class ReverseGeocode
|
||||
$sSQL = 'SELECT country_code FROM country_osm_grid';
|
||||
$sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.') LIMIT 1';
|
||||
|
||||
$sCountryCode = chksql(
|
||||
$this->oDB->getOne($sSQL),
|
||||
$sCountryCode = $this->oDB->getOne(
|
||||
$sSQL,
|
||||
null,
|
||||
'Could not determine country polygon containing the point.'
|
||||
);
|
||||
if ($sCountryCode) {
|
||||
@@ -115,10 +117,7 @@ class ReverseGeocode
|
||||
$sSQL .= ' LIMIT 1';
|
||||
|
||||
if (CONST_Debug) var_dump($sSQL);
|
||||
$aPlace = chksql(
|
||||
$this->oDB->getRow($sSQL),
|
||||
'Could not determine place node.'
|
||||
);
|
||||
$aPlace = $this->oDB->getRow($sSQL, null, 'Could not determine place node.');
|
||||
if ($aPlace) {
|
||||
return new Result($aPlace['place_id']);
|
||||
}
|
||||
@@ -134,10 +133,7 @@ class ReverseGeocode
|
||||
$sSQL .= ' ORDER BY distance ASC';
|
||||
|
||||
if (CONST_Debug) var_dump($sSQL);
|
||||
$aPlace = chksql(
|
||||
$this->oDB->getRow($sSQL),
|
||||
'Could not determine place node.'
|
||||
);
|
||||
$aPlace = $this->oDB->getRow($sSQL, null, 'Could not determine place node.');
|
||||
if ($aPlace) {
|
||||
return new Result($aPlace['place_id']);
|
||||
}
|
||||
@@ -178,10 +174,8 @@ class ReverseGeocode
|
||||
$sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.' )';
|
||||
$sSQL .= ' ORDER BY rank_address DESC LIMIT 1';
|
||||
|
||||
$aPoly = chksql(
|
||||
$this->oDB->getRow($sSQL),
|
||||
'Could not determine polygon containing the point.'
|
||||
);
|
||||
$aPoly = $this->oDB->getRow($sSQL, null, 'Could not determine polygon containing the point.');
|
||||
|
||||
if ($aPoly) {
|
||||
// if a polygon is found, search for placenodes begins ...
|
||||
$iParentPlaceID = $aPoly['parent_place_id'];
|
||||
@@ -213,10 +207,7 @@ class ReverseGeocode
|
||||
$sSQL .= ' LIMIT 1';
|
||||
|
||||
if (CONST_Debug) var_dump($sSQL);
|
||||
$aPlacNode = chksql(
|
||||
$this->oDB->getRow($sSQL),
|
||||
'Could not determine place node.'
|
||||
);
|
||||
$aPlacNode = $this->oDB->getRow($sSQL, null, 'Could not determine place node.');
|
||||
if ($aPlacNode) {
|
||||
return $aPlacNode;
|
||||
}
|
||||
@@ -271,10 +262,7 @@ class ReverseGeocode
|
||||
$sSQL .= ' OR ST_DWithin('.$sPointSQL.', centroid, '.$fSearchDiam.'))';
|
||||
$sSQL .= ' ORDER BY distance ASC limit 1';
|
||||
if (CONST_Debug) var_dump($sSQL);
|
||||
$aPlace = chksql(
|
||||
$this->oDB->getRow($sSQL),
|
||||
'Could not determine closest place.'
|
||||
);
|
||||
$aPlace = $this->oDB->getRow($sSQL, null, 'Could not determine closest place.');
|
||||
|
||||
if (CONST_Debug) var_dump($aPlace);
|
||||
if ($aPlace) {
|
||||
@@ -323,10 +311,7 @@ class ReverseGeocode
|
||||
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
|
||||
$sSQL .= ' ORDER BY distance ASC limit 1';
|
||||
if (CONST_Debug) var_dump($sSQL);
|
||||
$aStreet = chksql(
|
||||
$this->oDB->getRow($sSQL),
|
||||
'Could not determine closest place.'
|
||||
);
|
||||
$aStreet = $this->oDB->getRow($sSQL, null, 'Could not determine closest place.');
|
||||
if ($aStreet) {
|
||||
if (CONST_Debug) var_dump($aStreet);
|
||||
$oResult = new Result($aStreet['place_id']);
|
||||
@@ -347,10 +332,7 @@ class ReverseGeocode
|
||||
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)';
|
||||
$sSQL .= ' ORDER BY distance ASC limit 1';
|
||||
if (CONST_Debug) var_dump($sSQL);
|
||||
$aPlaceTiger = chksql(
|
||||
$this->oDB->getRow($sSQL),
|
||||
'Could not determine closest Tiger place.'
|
||||
);
|
||||
$aPlaceTiger = $this->oDB->getRow($sSQL, null, 'Could not determine closest Tiger place.');
|
||||
if ($aPlaceTiger) {
|
||||
if (CONST_Debug) var_dump('found Tiger housenumber', $aPlaceTiger);
|
||||
$oResult = new Result($aPlaceTiger['place_id'], Result::TABLE_TIGER);
|
||||
|
||||
@@ -126,7 +126,7 @@ class SearchContext
|
||||
* The viewbox may be bounded which means that no search results
|
||||
* must be outside the viewbox.
|
||||
*
|
||||
* @param object $oDB DB connection to use for computing the box.
|
||||
* @param object $oDB Nominatim::DB instance to use for computing the box.
|
||||
* @param string[] $aRoutePoints List of x,y coordinates along a route.
|
||||
* @param float $fRouteWidth Buffer around the route to use.
|
||||
* @param bool $bBounded True if the viewbox bounded.
|
||||
@@ -146,11 +146,11 @@ class SearchContext
|
||||
$this->sqlViewboxCentre .= ")'::geometry,4326)";
|
||||
|
||||
$sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/69).')';
|
||||
$sGeom = chksql($oDB->getOne('select '.$sSQL), 'Could not get small viewbox');
|
||||
$sGeom = $oDB->getOne('select '.$sSQL, null, 'Could not get small viewbox');
|
||||
$this->sqlViewboxSmall = "'".$sGeom."'::geometry";
|
||||
|
||||
$sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/30).')';
|
||||
$sGeom = chksql($oDB->getOne('select '.$sSQL), 'Could not get large viewbox');
|
||||
$sGeom = $oDB->getOne('select '.$sSQL, null, 'Could not get large viewbox');
|
||||
$this->sqlViewboxLarge = "'".$sGeom."'::geometry";
|
||||
}
|
||||
|
||||
|
||||
@@ -404,7 +404,7 @@ class SearchDescription
|
||||
/**
|
||||
* Query database for places that match this search.
|
||||
*
|
||||
* @param object $oDB Database connection to use.
|
||||
* @param object $oDB Nominatim::DB instance to use.
|
||||
* @param integer $iMinRank Minimum address rank to restrict search to.
|
||||
* @param integer $iMaxRank Maximum address rank to restrict search to.
|
||||
* @param integer $iLimit Maximum number of results.
|
||||
@@ -479,7 +479,7 @@ class SearchDescription
|
||||
$sSQL .= ' WHERE place_id in ('.$sPlaceIds.')';
|
||||
$sSQL .= " AND postcode != '".$this->sPostcode."'";
|
||||
Debug::printSQL($sSQL);
|
||||
$aFilteredPlaceIDs = chksql($oDB->getCol($sSQL));
|
||||
$aFilteredPlaceIDs = $oDB->getCol($sSQL);
|
||||
if ($aFilteredPlaceIDs) {
|
||||
foreach ($aFilteredPlaceIDs as $iPlaceId) {
|
||||
$aResults[$iPlaceId]->iResultRank++;
|
||||
@@ -523,8 +523,7 @@ class SearchDescription
|
||||
$aDBResults = array();
|
||||
$sPoiTable = $this->poiTable();
|
||||
|
||||
$sSQL = 'SELECT count(*) FROM pg_tables WHERE tablename = \''.$sPoiTable."'";
|
||||
if (chksql($oDB->getOne($sSQL))) {
|
||||
if ($oDB->tableExists($sPoiTable)) {
|
||||
$sSQL = 'SELECT place_id FROM '.$sPoiTable.' ct';
|
||||
if ($this->oContext->sqlCountryList) {
|
||||
$sSQL .= ' JOIN placex USING (place_id)';
|
||||
@@ -544,14 +543,14 @@ class SearchDescription
|
||||
} elseif ($this->oContext->hasNearPoint()) {
|
||||
$sSQL .= ' ORDER BY '.$this->oContext->distanceSQL('ct.centroid').' ASC';
|
||||
}
|
||||
$sSQL .= " limit $iLimit";
|
||||
$sSQL .= " LIMIT $iLimit";
|
||||
Debug::printSQL($sSQL);
|
||||
$aDBResults = chksql($oDB->getCol($sSQL));
|
||||
$aDBResults = $oDB->getCol($sSQL);
|
||||
}
|
||||
|
||||
if ($this->oContext->hasNearPoint()) {
|
||||
$sSQL = 'SELECT place_id FROM placex WHERE ';
|
||||
$sSQL .= 'class=\''.$this->sClass."' and type='".$this->sType."'";
|
||||
$sSQL .= 'class = :class and type = :type';
|
||||
$sSQL .= ' AND '.$this->oContext->withinSQL('geometry');
|
||||
$sSQL .= ' AND linked_place_id is null';
|
||||
if ($this->oContext->sqlCountryList) {
|
||||
@@ -560,7 +559,10 @@ class SearchDescription
|
||||
$sSQL .= ' ORDER BY '.$this->oContext->distanceSQL('centroid').' ASC';
|
||||
$sSQL .= " LIMIT $iLimit";
|
||||
Debug::printSQL($sSQL);
|
||||
$aDBResults = chksql($oDB->getCol($sSQL));
|
||||
$aDBResults = $oDB->getCol(
|
||||
$sSQL,
|
||||
array(':class' => $this->sClass, ':type' => $this->sType)
|
||||
);
|
||||
}
|
||||
|
||||
$aResults = array();
|
||||
@@ -592,7 +594,7 @@ class SearchDescription
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
$aResults = array();
|
||||
foreach (chksql($oDB->getCol($sSQL)) as $iPlaceId) {
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$aResults[$iPlaceId] = new Result($iPlaceId, Result::TABLE_POSTCODE);
|
||||
}
|
||||
|
||||
@@ -722,10 +724,7 @@ class SearchDescription
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
$aDBResults = chksql(
|
||||
$oDB->getAll($sSQL),
|
||||
'Could not get places for search terms.'
|
||||
);
|
||||
$aDBResults = $oDB->getAll($sSQL, null, 'Could not get places for search terms.');
|
||||
|
||||
foreach ($aDBResults as $aResult) {
|
||||
$oResult = new Result($aResult['place_id']);
|
||||
@@ -755,7 +754,7 @@ class SearchDescription
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
// XXX should inherit the exactMatches from its parent
|
||||
foreach (chksql($oDB->getCol($sSQL)) as $iPlaceId) {
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$aResults[$iPlaceId] = new Result($iPlaceId);
|
||||
}
|
||||
|
||||
@@ -781,7 +780,7 @@ class SearchDescription
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
foreach (chksql($oDB->getCol($sSQL)) as $iPlaceId) {
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$oResult = new Result($iPlaceId, Result::TABLE_OSMLINE);
|
||||
$oResult->iHouseNumber = $iHousenumber;
|
||||
$aResults[$iPlaceId] = $oResult;
|
||||
@@ -797,7 +796,7 @@ class SearchDescription
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
foreach (chksql($oDB->getCol($sSQL)) as $iPlaceId) {
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$aResults[$iPlaceId] = new Result($iPlaceId, Result::TABLE_AUX);
|
||||
}
|
||||
}
|
||||
@@ -818,7 +817,7 @@ class SearchDescription
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
foreach (chksql($oDB->getCol($sSQL)) as $iPlaceId) {
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$oResult = new Result($iPlaceId, Result::TABLE_TIGER);
|
||||
$oResult->iHouseNumber = $iHousenumber;
|
||||
$aResults[$iPlaceId] = $oResult;
|
||||
@@ -852,7 +851,7 @@ class SearchDescription
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
foreach (chksql($oDB->getCol($sSQL)) as $iPlaceId) {
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$aResults[$iPlaceId] = new Result($iPlaceId);
|
||||
}
|
||||
}
|
||||
@@ -860,12 +859,11 @@ class SearchDescription
|
||||
// NEAR and IN are handled the same
|
||||
if ($this->iOperator == Operator::TYPE || $this->iOperator == Operator::NEAR) {
|
||||
$sClassTable = $this->poiTable();
|
||||
$sSQL = "SELECT count(*) FROM pg_tables WHERE tablename = '$sClassTable'";
|
||||
$bCacheTable = (bool) chksql($oDB->getOne($sSQL));
|
||||
$bCacheTable = $oDB->tableExists($sClassTable);
|
||||
|
||||
$sSQL = "SELECT min(rank_search) FROM placex WHERE place_id in ($sPlaceIDs)";
|
||||
Debug::printSQL($sSQL);
|
||||
$iMaxRank = (int)chksql($oDB->getOne($sSQL));
|
||||
$iMaxRank = (int) $oDB->getOne($sSQL);
|
||||
|
||||
// For state / country level searches the normal radius search doesn't work very well
|
||||
$sPlaceGeom = false;
|
||||
@@ -878,7 +876,7 @@ class SearchDescription
|
||||
$sSQL .= ' ORDER BY rank_search ASC ';
|
||||
$sSQL .= ' LIMIT 1';
|
||||
Debug::printSQL($sSQL);
|
||||
$sPlaceGeom = chksql($oDB->getOne($sSQL));
|
||||
$sPlaceGeom = $oDB->getOne($sSQL);
|
||||
}
|
||||
|
||||
if ($sPlaceGeom) {
|
||||
@@ -888,7 +886,7 @@ class SearchDescription
|
||||
$sSQL = 'SELECT place_id FROM placex';
|
||||
$sSQL .= " WHERE place_id in ($sPlaceIDs) and rank_search < $iMaxRank";
|
||||
Debug::printSQL($sSQL);
|
||||
$aPlaceIDs = chksql($oDB->getCol($sSQL));
|
||||
$aPlaceIDs = $oDB->getCol($sSQL);
|
||||
$sPlaceIDs = join(',', $aPlaceIDs);
|
||||
}
|
||||
|
||||
@@ -934,7 +932,7 @@ class SearchDescription
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
foreach (chksql($oDB->getCol($sSQL)) as $iPlaceId) {
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$aResults[$iPlaceId] = new Result($iPlaceId);
|
||||
}
|
||||
} else {
|
||||
@@ -966,7 +964,7 @@ class SearchDescription
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
foreach (chksql($oDB->getCol($sSQL)) as $iPlaceId) {
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$aResults[$iPlaceId] = new Result($iPlaceId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class TokenList
|
||||
/**
|
||||
* Add token information from the word table in the database.
|
||||
*
|
||||
* @param object $oDB Database connection.
|
||||
* @param object $oDB Nominatim::DB instance.
|
||||
* @param string[] $aTokens List of tokens to look up in the database.
|
||||
* @param string[] $aCountryCodes List of country restrictions.
|
||||
* @param string $sNormQuery Normalized query string.
|
||||
@@ -89,7 +89,7 @@ class TokenList
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
$aDBWords = chksql($oDB->getAll($sSQL), 'Could not get word tokens.');
|
||||
$aDBWords = $oDB->getAll($sSQL, null, 'Could not get word tokens.');
|
||||
|
||||
foreach ($aDBWords as $aWord) {
|
||||
$oToken = null;
|
||||
|
||||
@@ -120,11 +120,6 @@ function showUsage($aSpec, $bExit = false, $sError = false)
|
||||
exit;
|
||||
}
|
||||
|
||||
function chksql($oSql, $sMsg = false)
|
||||
{
|
||||
return $oSql;
|
||||
}
|
||||
|
||||
function info($sMsg)
|
||||
{
|
||||
echo date('Y-m-d H:i:s == ').$sMsg."\n";
|
||||
|
||||
176
lib/db.php
176
lib/db.php
@@ -1,176 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
require_once(CONST_BasePath.'/lib/DatabaseError.php');
|
||||
|
||||
class DB
|
||||
{
|
||||
public $connection;
|
||||
|
||||
public function __construct($sDSN = CONST_Database_DSN)
|
||||
{
|
||||
$this->sDSN = $sDSN;
|
||||
}
|
||||
|
||||
public function connect($bNew = false, $bPersistent = true)
|
||||
{
|
||||
$aConnOptions = array(
|
||||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
||||
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
|
||||
\PDO::ATTR_PERSISTENT => $bPersistent
|
||||
);
|
||||
|
||||
// https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php
|
||||
try {
|
||||
$conn = new \PDO($this->sDSN, null, null, $aConnOptions);
|
||||
} catch (\PDOException $e) {
|
||||
$sMsg = 'Failed to establish database connection:' . $e->getMessage();
|
||||
throw new \Nominatim\DatabaseError($sMsg, 500, null, $e->getMessage());
|
||||
}
|
||||
|
||||
$conn->exec("SET DateStyle TO 'sql,european'");
|
||||
$conn->exec("SET client_encoding TO 'utf-8'");
|
||||
$iMaxExecution = ini_get('max_execution_time');
|
||||
if ($iMaxExecution > 0) $conn->setAttribute(\PDO::ATTR_TIMEOUT, $iMaxExecution); // seconds
|
||||
|
||||
$this->connection = $conn;
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns the number of rows that were modified or deleted by the SQL
|
||||
// statement. If no rows were affected returns 0.
|
||||
public function exec($sSQL)
|
||||
{
|
||||
$val = null;
|
||||
try {
|
||||
$val = $this->connection->exec($sSQL);
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError('Database query failed', 500, null, $e, $sSQL);
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function getRow($sSQL)
|
||||
{
|
||||
try {
|
||||
$stmt = $this->connection->query($sSQL);
|
||||
$row = $stmt->fetch();
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError('Database query failed', 500, null, $e, $sSQL);
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
public function getOne($sSQL)
|
||||
{
|
||||
try {
|
||||
$stmt = $this->connection->query($sSQL);
|
||||
$row = $stmt->fetch(\PDO::FETCH_NUM);
|
||||
if ($row === false) return false;
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError('Database query failed', 500, null, $e, $sSQL);
|
||||
}
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
public function getAll($sSQL)
|
||||
{
|
||||
try {
|
||||
$stmt = $this->connection->query($sSQL);
|
||||
$rows = $stmt->fetchAll();
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError('Database query failed', 500, null, $e, $sSQL);
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public function getCol($sSQL)
|
||||
{
|
||||
$aVals = array();
|
||||
try {
|
||||
$stmt = $this->connection->query($sSQL);
|
||||
while ($val = $stmt->fetchColumn(0)) { // returns first column or false
|
||||
$aVals[] = $val;
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError('Database query failed', 500, null, $e, $sSQL);
|
||||
}
|
||||
return $aVals;
|
||||
}
|
||||
|
||||
public function getAssoc($sSQL)
|
||||
{
|
||||
try {
|
||||
$stmt = $this->connection->query($sSQL);
|
||||
$aList = array();
|
||||
while ($aRow = $stmt->fetch(\PDO::FETCH_NUM)) {
|
||||
$aList[$aRow[0]] = $aRow[1];
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
throw new \Nominatim\DatabaseError('Database query failed', 500, null, $e, $sSQL);
|
||||
}
|
||||
return $aList;
|
||||
}
|
||||
|
||||
|
||||
// St. John's Way => 'St. John\'s Way'
|
||||
public function getDBQuoted($sVal)
|
||||
{
|
||||
return $this->connection->quote($sVal);
|
||||
}
|
||||
|
||||
public function getDBQuotedList($aVals)
|
||||
{
|
||||
return array_map(function ($sVal) {
|
||||
return $this->getDBQuoted($sVal);
|
||||
}, $aVals);
|
||||
}
|
||||
|
||||
public function getArraySQL($a)
|
||||
{
|
||||
return 'ARRAY['.join(',', $a).']';
|
||||
}
|
||||
|
||||
public function getLastError()
|
||||
{
|
||||
// https://secure.php.net/manual/en/pdo.errorinfo.php
|
||||
return $this->connection->errorInfo();
|
||||
}
|
||||
|
||||
public function tableExists($sTableName)
|
||||
{
|
||||
$sSQL = 'SELECT count(*) FROM pg_tables WHERE tablename = '.$this->getDBQuoted($sTableName);
|
||||
return ($this->getOne($sSQL) == 1);
|
||||
}
|
||||
|
||||
public function getPostgresVersion()
|
||||
{
|
||||
$sVersionString = $this->getOne('SHOW server_version_num');
|
||||
preg_match('#([0-9]?[0-9])([0-9][0-9])[0-9][0-9]#', $sVersionString, $aMatches);
|
||||
return (float) ($aMatches[1].'.'.$aMatches[2]);
|
||||
}
|
||||
|
||||
public function getPostgisVersion()
|
||||
{
|
||||
$sVersionString = $this->getOne('select postgis_lib_version()');
|
||||
preg_match('#^([0-9]+)[.]([0-9]+)[.]#', $sVersionString, $aMatches);
|
||||
return (float) ($aMatches[1].'.'.$aMatches[2]);
|
||||
}
|
||||
|
||||
public static function parseDSN($sDSN)
|
||||
{
|
||||
// https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php
|
||||
$aInfo = array();
|
||||
if (preg_match('/^pgsql:(.+)/', $sDSN, $aMatches)) {
|
||||
foreach (explode(';', $aMatches[1]) as $sKeyVal) {
|
||||
list($sKey, $sVal) = explode('=', $sKeyVal, 2);
|
||||
if ($sKey == 'host') $sKey = 'hostspec';
|
||||
if ($sKey == 'dbname') $sKey = 'database';
|
||||
if ($sKey == 'user') $sKey = 'username';
|
||||
$aInfo[$sKey] = $sVal;
|
||||
}
|
||||
}
|
||||
return $aInfo;
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,6 @@ require_once(CONST_Debug ? 'DebugHtml.php' : 'DebugNone.php');
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
function chksql($oSql, $sMsg = 'Database request failed')
|
||||
{
|
||||
return $oSql;
|
||||
}
|
||||
|
||||
|
||||
function userError($sMsg)
|
||||
{
|
||||
throw new Exception($sMsg, 400);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
require_once(CONST_BasePath.'/lib/lib.php');
|
||||
require_once(CONST_BasePath.'/lib/db.php');
|
||||
require_once(CONST_BasePath.'/lib/DB.php');
|
||||
|
||||
if (get_magic_quotes_gpc()) {
|
||||
echo "Please disable magic quotes in your php.ini configuration\n";
|
||||
|
||||
@@ -53,14 +53,14 @@ class AddressLevelParser
|
||||
*/
|
||||
public function createTable($oDB, $sTable)
|
||||
{
|
||||
chksql($oDB->exec('DROP TABLE IF EXISTS '.$sTable));
|
||||
$oDB->exec('DROP TABLE IF EXISTS '.$sTable);
|
||||
$sSql = 'CREATE TABLE '.$sTable;
|
||||
$sSql .= '(country_code varchar(2), class TEXT, type TEXT,';
|
||||
$sSql .= ' rank_search SMALLINT, rank_address SMALLINT)';
|
||||
chksql($oDB->exec($sSql));
|
||||
$oDB->exec($sSql);
|
||||
|
||||
$sSql = 'CREATE UNIQUE INDEX ON '.$sTable.'(country_code, class, type)';
|
||||
chksql($oDB->exec($sSql));
|
||||
$sSql = 'CREATE UNIQUE INDEX ON '.$sTable.' (country_code, class, type)';
|
||||
$oDB->exec($sSql);
|
||||
|
||||
$sSql = 'INSERT INTO '.$sTable.' VALUES ';
|
||||
foreach ($this->aLevels as $aLevel) {
|
||||
@@ -93,6 +93,6 @@ class AddressLevelParser
|
||||
}
|
||||
}
|
||||
}
|
||||
chksql($oDB->exec(rtrim($sSql, ',')));
|
||||
$oDB->exec(rtrim($sSql, ','));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,15 +74,9 @@ class SetupFunctions
|
||||
public function createDB()
|
||||
{
|
||||
info('Create DB');
|
||||
$bExists = true;
|
||||
try {
|
||||
$oDB = new \Nominatim\DB;
|
||||
$oDB->connect();
|
||||
} catch (\Nominatim\DatabaseError $e) {
|
||||
$bExists = false;
|
||||
}
|
||||
$oDB = new \Nominatim\DB;
|
||||
|
||||
if ($bExists) {
|
||||
if ($oDB->databaseExists()) {
|
||||
fail('database already exists ('.CONST_Database_DSN.')');
|
||||
}
|
||||
|
||||
@@ -122,7 +116,7 @@ class SetupFunctions
|
||||
// For extratags and namedetails the hstore_to_json converter is
|
||||
// needed which is only available from Postgresql 9.3+. For older
|
||||
// versions add a dummy function that returns nothing.
|
||||
$iNumFunc = chksql($this->oDB->getOne("select count(*) from pg_proc where proname = 'hstore_to_json'"));
|
||||
$iNumFunc = $this->oDB->getOne("select count(*) from pg_proc where proname = 'hstore_to_json'");
|
||||
|
||||
if ($iNumFunc == 0) {
|
||||
$this->pgsqlRunScript("create function hstore_to_json(dummy hstore) returns text AS 'select null::text' language sql immutable");
|
||||
@@ -142,7 +136,7 @@ class SetupFunctions
|
||||
$this->pgsqlRunScript('ALTER FUNCTION ST_Distance_Spheroid(geometry, geometry, spheroid) RENAME TO ST_DistanceSpheroid');
|
||||
}
|
||||
|
||||
$i = chksql($this->oDB->getOne("select count(*) from pg_user where usename = '".CONST_Database_Web_User."'"));
|
||||
$i = $this->oDB->getOne("select count(*) from pg_user where usename = '".CONST_Database_Web_User."'");
|
||||
if ($i == 0) {
|
||||
echo "\nERROR: Web user '".CONST_Database_Web_User."' does not exist. Create it with:\n";
|
||||
echo "\n createuser ".CONST_Database_Web_User."\n\n";
|
||||
@@ -224,7 +218,7 @@ class SetupFunctions
|
||||
|
||||
$this->runWithPgEnv($osm2pgsql);
|
||||
|
||||
if (!$this->sIgnoreErrors && !chksql($this->oDB->getRow('select * from place limit 1'))) {
|
||||
if (!$this->sIgnoreErrors && !$this->oDB->getRow('select * from place limit 1')) {
|
||||
fail('No Data');
|
||||
}
|
||||
}
|
||||
@@ -386,7 +380,7 @@ class SetupFunctions
|
||||
echo '.';
|
||||
|
||||
$sSQL = 'select distinct partition from country_name';
|
||||
$aPartitions = chksql($this->oDB->getCol($sSQL));
|
||||
$aPartitions = $this->oDB->getCol($sSQL);
|
||||
|
||||
if (!$this->bNoPartitions) $aPartitions[] = 0;
|
||||
foreach ($aPartitions as $sPartition) {
|
||||
@@ -734,7 +728,7 @@ class SetupFunctions
|
||||
);
|
||||
|
||||
$aDropTables = array();
|
||||
$aHaveTables = chksql($this->oDB->getCol("SELECT tablename FROM pg_tables WHERE schemaname='public'"));
|
||||
$aHaveTables = $this->oDB->getCol("SELECT tablename FROM pg_tables WHERE schemaname='public'");
|
||||
|
||||
foreach ($aHaveTables as $sTable) {
|
||||
$bFound = false;
|
||||
|
||||
Reference in New Issue
Block a user