icingaweb2/library/Icinga/Data/Db/DbConnection.php
Thomas Gelf 7b77083c89 Data\Db\DbConnection: relax timeout, persistance
Raised connection timeout, helps when talking to DB servers behind
weak links. Please note that I'm not sure whether this really is a
better default.

While it doesn't matter with local sockets, connection overhead will
have an impact with remote database servers. We have to reconnect with
every single request. Persistent connections seem to be no longer as
errorprone as they used to be, but I'd still refuse to switch them on
by default.

What we need is a config setting for connection persistancy and wizards
strongly suggesting to use this when working with remote db servers.
2014-06-17 09:53:59 +00:00

280 lines
7.8 KiB
PHP

<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Data\Db;
use Icinga\Application\Benchmark;
use Icinga\Data\Db\DbQuery;
use Icinga\Data\ResourceFactory;
use Icinga\Data\Selectable;
use Icinga\Exception\ConfigurationError;
use PDO;
use Zend_Config;
use Zend_Db;
/**
* Encapsulate database connections and query creation
*/
class DbConnection implements Selectable
{
/**
* Connection config
*
* @var Zend_Config
*/
private $config;
/**
* Database type
*
* @var string
*/
private $dbType;
/**
* @var Zend_Db_Adapter_Abstract
*/
private $dbAdapter;
/**
* Table prefix
*
* @var string
*/
private $tablePrefix = '';
private static $genericAdapterOptions = array(
Zend_Db::AUTO_QUOTE_IDENTIFIERS => false,
Zend_Db::CASE_FOLDING => Zend_Db::CASE_LOWER
);
private static $driverOptions = array(
PDO::ATTR_TIMEOUT => 10,
PDO::ATTR_CASE => PDO::CASE_LOWER,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// TODO: allow configurable PDO::ATTR_PERSISTENT => true
);
/**
* Create a new connection object
*
* @param Zend_Config $config
*/
public function __construct(Zend_Config $config = null)
{
$this->config = $config;
$this->connect();
}
/**
* Provide a query on this connection
*
* @return Query
*/
public function select()
{
return new DbQuery($this);
}
/**
* Getter for database type
*
* @return string
*/
public function getDbType()
{
return $this->dbType;
}
/**
* Getter for the Zend_Db_Adapter
*
* @return Zend_Db_Adapter_Abstract
*/
public function getDbAdapter()
{
return $this->dbAdapter;
}
/**
* Create a new connection
*/
private function connect()
{
$genericAdapterOptions = self::$genericAdapterOptions;
$driverOptions = self::$driverOptions;
$adapterParamaters = array(
'host' => $this->config->host,
'username' => $this->config->username,
'password' => $this->config->password,
'dbname' => $this->config->dbname,
'options' => & $genericAdapterOptions,
'driver_options' => & $driverOptions
);
$this->dbType = strtolower($this->config->get('db', 'mysql'));
switch ($this->dbType) {
case 'mysql':
$adapter = 'Pdo_Mysql';
/*
* Set MySQL server SQL modes to behave as closely as possible to Oracle and PostgreSQL. Note that the
* ONLY_FULL_GROUP_BY mode is left on purpose because MySQL requires you to specify all non-aggregate
* columns in the group by list even if the query is grouped by the master table's primary key which is
* valid ANSI SQL though. Further in that case the query plan would suffer if you add more columns to
* the group by list.
*/
$driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] =
'SET SESSION SQL_MODE=\'STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,'
. 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\';';
$adapterParamaters['port'] = $this->config->get('port', 3306);
break;
case 'pgsql':
$adapter = 'Pdo_Pgsql';
$adapterParamaters['port'] = $this->config->get('port', 5432);
break;
/*case 'oracle':
if ($this->dbtype === 'oracle') {
$attributes['persistent'] = true;
}
$this->db = ZfDb::factory($adapter, $attributes);
if ($adapter === 'Oracle') {
$this->db->setLobAsString(false);
}
break;*/
default:
throw new ConfigurationError(sprintf('Backend "%s" is not supported', $this->dbType));
}
$this->dbAdapter = Zend_Db::factory($adapter, $adapterParamaters);
$this->dbAdapter->setFetchMode(Zend_Db::FETCH_OBJ);
// TODO(el/tg): The profiler is disabled per default, why do we disable the profiler explicitly?
$this->dbAdapter->getProfiler()->setEnabled(false);
}
public static function fromResourceName($name)
{
return new static(ResourceFactory::getResourceConfig($name));
}
/**
* @deprecated Use Connection::getDbAdapter() instead
*/
public function getConnection()
{
return $this->dbAdapter;
}
/**
* Getter for the table prefix
*
* @return string
*/
public function getTablePrefix()
{
return $this->tablePrefix;
}
/**
* Setter for the table prefix
*
* @param string $prefix
*
* @return self
*/
public function setTablePrefix($prefix)
{
$this->tablePrefix = $prefix;
return $this;
}
/**
* Retrieve an array containing all rows of the result set
*
* @param DbQuery $query
*
* @return array
*/
public function fetchAll(DbQuery $query)
{
Benchmark::measure('DB is fetching All');
$result = $this->dbAdapter->fetchAll($query->getSelectQuery());
Benchmark::measure('DB fetch done');
return $result;
}
/**
* Fetch the first row of the result set
*
* @param DbQuery $query
*
* @return mixed
*/
public function fetchRow(DbQuery $query)
{
return $this->dbAdapter->fetchRow($query->getSelectQuery());
}
/**
* Fetch a column of all rows of the result set as an array
*
* @param DbQuery $query
* @param int $columnIndex Index of the column to fetch
*
* @return array
*/
public function fetchColumn(DbQuery $query, $columnIndex = 0)
{
return $this->dbAdapter->fetchCol($query->getSelectQuery());
}
/**
* Fetch the first column of the first row of the result set
*
* @param DbQuery $query
*
* @return string
*/
public function fetchOne(DbQuery $query)
{
return $this->dbAdapter->fetchOne($query->getSelectQuery());
}
/**
* Fetch all rows of the result set as an array of key-value pairs
*
* The first column is the key, the second column is the value.
*
* @param DbQuery $query
*
* @return array
*/
public function fetchPairs(DbQuery $query)
{
return $this->dbAdapter->fetchPairs($query->getSelectQuery());
}
}