5 require_once(CONST_BasePath.'/lib/DatabaseError.php');
8 * Uses PDO to access the database specified in the CONST_Database_DSN
13 protected $connection;
15 public function __construct($sDSN = CONST_Database_DSN)
20 public function connect($bNew = false, $bPersistent = true)
22 if (isset($this->connection) && !$bNew) {
25 $aConnOptions = array(
26 \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
27 \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
28 \PDO::ATTR_PERSISTENT => $bPersistent
31 // https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php
33 $conn = new \PDO($this->sDSN, null, null, $aConnOptions);
34 } catch (\PDOException $e) {
35 $sMsg = 'Failed to establish database connection:' . $e->getMessage();
36 throw new \Nominatim\DatabaseError($sMsg, 500, null, $e->getMessage());
39 $conn->exec("SET DateStyle TO 'sql,european'");
40 $conn->exec("SET client_encoding TO 'utf-8'");
41 $iMaxExecution = ini_get('max_execution_time');
42 if ($iMaxExecution > 0) $conn->setAttribute(\PDO::ATTR_TIMEOUT, $iMaxExecution); // seconds
44 $this->connection = $conn;
48 // returns the number of rows that were modified or deleted by the SQL
49 // statement. If no rows were affected returns 0.
50 public function exec($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
54 if (isset($aInputVars)) {
55 $stmt = $this->connection->prepare($sSQL);
56 $stmt->execute($aInputVars);
58 $val = $this->connection->exec($sSQL);
60 } catch (\PDOException $e) {
61 $sErrMessage = $e->message();
62 throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
68 * Executes query. Returns first row as array.
69 * Returns false if no result found.
75 public function getRow($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
78 if (isset($aInputVars)) {
79 $stmt = $this->connection->prepare($sSQL);
80 $stmt->execute($aInputVars);
82 $stmt = $this->connection->query($sSQL);
84 $row = $stmt->fetch();
85 } catch (\PDOException $e) {
86 throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
92 * Executes query. Returns first value of first result.
93 * Returns false if no results found.
99 public function getOne($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
102 if (isset($aInputVars)) {
103 $stmt = $this->connection->prepare($sSQL);
104 $stmt->execute($aInputVars);
106 $stmt = $this->connection->query($sSQL);
108 $row = $stmt->fetch(\PDO::FETCH_NUM);
109 if ($row === false) return false;
110 } catch (\PDOException $e) {
111 throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
117 * Executes query. Returns array of results (arrays).
118 * Returns empty array if no results found.
120 * @param string $sSQL
124 public function getAll($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
127 if (isset($aInputVars)) {
128 $stmt = $this->connection->prepare($sSQL);
129 $stmt->execute($aInputVars);
131 $stmt = $this->connection->query($sSQL);
133 $rows = $stmt->fetchAll();
134 } catch (\PDOException $e) {
135 throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
141 * Executes query. Returns array of the first value of each result.
142 * Returns empty array if no results found.
144 * @param string $sSQL
148 public function getCol($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
152 if (isset($aInputVars)) {
153 $stmt = $this->connection->prepare($sSQL);
154 $stmt->execute($aInputVars);
156 $stmt = $this->connection->query($sSQL);
158 while ($val = $stmt->fetchColumn(0)) { // returns first column or false
161 } catch (\PDOException $e) {
162 throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
168 * Executes query. Returns associate array mapping first value to second value of each result.
169 * Returns empty array if no results found.
171 * @param string $sSQL
175 public function getAssoc($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
178 if (isset($aInputVars)) {
179 $stmt = $this->connection->prepare($sSQL);
180 $stmt->execute($aInputVars);
182 $stmt = $this->connection->query($sSQL);
185 while ($aRow = $stmt->fetch(\PDO::FETCH_NUM)) {
186 $aList[$aRow[0]] = $aRow[1];
188 } catch (\PDOException $e) {
189 throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
196 * St. John's Way => 'St. John\'s Way'
198 * @param string $sVal Text to be quoted.
202 public function getDBQuoted($sVal)
204 return $this->connection->quote($sVal);
208 * Like getDBQuoted, but takes an array.
210 * @param array $aVals List of text to be quoted.
214 public function getDBQuotedList($aVals)
216 return array_map(function ($sVal) {
217 return $this->getDBQuoted($sVal);
222 * [1,2,'b'] => 'ARRAY[1,2,'b']''
224 * @param array $aVals List of text to be quoted.
228 public function getArraySQL($a)
230 return 'ARRAY['.join(',', $a).']';
233 public function getLastError()
235 // https://secure.php.net/manual/en/pdo.errorinfo.php
236 return $this->connection->errorInfo();
240 * Check if a table exists in the database. Returns true if it does.
242 * @param string $sTableName
246 public function tableExists($sTableName)
248 $sSQL = 'SELECT count(*) FROM pg_tables WHERE tablename = :tablename';
249 return ($this->getOne($sSQL, array(':tablename' => $sTableName)) == 1);
253 * Since the DSN includes the database name, checks if the connection works.
257 public function databaseExists()
261 $this->connect(true);
262 } catch (\Nominatim\DatabaseError $e) {
273 public function getPostgresVersion()
275 $sVersionString = $this->getOne('SHOW server_version_num');
276 preg_match('#([0-9]?[0-9])([0-9][0-9])[0-9][0-9]#', $sVersionString, $aMatches);
277 return (float) ($aMatches[1].'.'.$aMatches[2]);
285 public function getPostgisVersion()
287 $sVersionString = $this->getOne('select postgis_lib_version()');
288 preg_match('#^([0-9]+)[.]([0-9]+)[.]#', $sVersionString, $aMatches);
289 return (float) ($aMatches[1].'.'.$aMatches[2]);
292 public static function parseDSN($sDSN)
294 // https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php
296 if (preg_match('/^pgsql:(.+)/', $sDSN, $aMatches)) {
297 foreach (explode(';', $aMatches[1]) as $sKeyVal) {
298 list($sKey, $sVal) = explode('=', $sKeyVal, 2);
299 if ($sKey == 'host') $sKey = 'hostspec';
300 if ($sKey == 'dbname') $sKey = 'database';
301 if ($sKey == 'user') $sKey = 'username';
302 $aInfo[$sKey] = $sVal;