Nominatim::DB support input variables, custom error messages

This commit is contained in:
marc tobias
2019-03-10 15:42:58 +01:00
parent 75f951d254
commit 890d415e1f
24 changed files with 468 additions and 328 deletions

View File

@@ -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
View 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;
}
}

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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";
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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";

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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";

View File

@@ -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, ','));
}
}

View File

@@ -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;