<?php
-require_once('DB.php');
+namespace Nominatim;
+require_once(CONST_BasePath.'/lib/DatabaseError.php');
-function &getDB($bNew = false, $bPersistent = false)
+class DB
{
- // Get the database object
- $oDB = chksql(
- DB::connect(CONST_Database_DSN.($bNew?'?new_link=true':''), $bPersistent),
- "Failed to establish database connection"
- );
- $oDB->setFetchMode(DB_FETCHMODE_ASSOC);
- $oDB->query("SET DateStyle TO 'sql,european'");
- $oDB->query("SET client_encoding TO 'utf-8'");
- $iMaxExecution = ini_get('max_execution_time') * 1000;
- if ($iMaxExecution > 0) $oDB->query("SET statement_timeout TO $iMaxExecution");
- return $oDB;
-}
+ public $connection;
-function getDBQuoted($s)
-{
- return "'".pg_escape_string($s)."'";
-}
+ public function __construct($sDSN = CONST_Database_DSN)
+ {
+ $this->sDSN = $sDSN;
+ }
-function getPostgresVersion(&$oDB)
-{
- $sVersionString = $oDB->getOne('select version()');
- preg_match('#PostgreSQL ([0-9]+)[.]([0-9]+)[^0-9]#', $sVersionString, $aMatches);
- return (float) ($aMatches[1].'.'.$aMatches[2]);
-}
+ 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
+ );
-function getPostgisVersion(&$oDB)
-{
- $sVersionString = $oDB->getOne('select postgis_full_version()');
- preg_match('#POSTGIS="([0-9]+)[.]([0-9]+)[.]([0-9]+)( r([0-9]+))?"#', $sVersionString, $aMatches);
- return (float) ($aMatches[1].'.'.$aMatches[2]);
+ // 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;
+ }
}