From 82b5e16de8f83c432be6b66ea54dc041a1fb0b92 Mon Sep 17 00:00:00 2001 From: "Michael J. Rubinsky" Date: Fri, 22 Oct 2010 09:49:22 -0400 Subject: [PATCH] Add a multi-adapter implementation of Horde_Db_Adapter to support splitread --- framework/Core/lib/Horde/Core/Factory/Db.php | 10 +- framework/Db/lib/Horde/Db/Adapter/SplitRead.php | 418 ++++++++++++++++++++++++ framework/Db/package.xml | 211 +++++++++--- 3 files changed, 591 insertions(+), 48 deletions(-) create mode 100644 framework/Db/lib/Horde/Db/Adapter/SplitRead.php diff --git a/framework/Core/lib/Horde/Core/Factory/Db.php b/framework/Core/lib/Horde/Core/Factory/Db.php index 79c0ea62c..7c5c17e2b 100644 --- a/framework/Core/lib/Horde/Core/Factory/Db.php +++ b/framework/Core/lib/Horde/Core/Factory/Db.php @@ -112,10 +112,13 @@ class Horde_Core_Factory_Db */ protected function _createDb($config) { + // Split read? if (!empty($config['splitread'])) { unset($config['splitread']); - $config['write_db'] = $this->_createDb($config); + $write_db = $this->_createDb($config); $config = array_merge($config, $config['read']); + $read_db = $this->_createDb($config); + return new Horde_Db_Adapter_SplitRead($read_db, $write_db); } if (!isset($config['adapter'])) { @@ -143,10 +146,7 @@ class Horde_Core_Factory_Db $class = 'Horde_Db_Adapter_' . $adapter; if (class_exists($class)) { - unset($config['read'], - $config['write_db'], - $config['hostspec'], - $config['splitread']); + unset($config['hostspec'], $config['splitread']); $ob = new $class($config); if (!isset($config['cache'])) { diff --git a/framework/Db/lib/Horde/Db/Adapter/SplitRead.php b/framework/Db/lib/Horde/Db/Adapter/SplitRead.php new file mode 100644 index 000000000..903929e04 --- /dev/null +++ b/framework/Db/lib/Horde/Db/Adapter/SplitRead.php @@ -0,0 +1,418 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @author Michael J. Rubinsky + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ + +/** + * The Horde_Db_Adapter_SplitRead:: class wraps two individual adapters to + * provide support for split read/write database setups. + * + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @author Michael J. Rubinsky + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ +class Horde_Db_Adapter_SplitRead implements Horde_Db_Adapter +{ + /** + * The read adapter + * + * @var Horde_Db_Adapter + */ + private $_read; + + /** + * The write adapter + * + * @var Horde_Db_Adapter + */ + private $_write; + + /** + * Const'r + * + * @param Horde_Db_Adapter $read + * @param Horde_Db_Adapter $write + */ + public function __construct(Horde_Db_Adapter $read, Horde_Db_Adapter $write) + { + $this->_read = $read; + $this->_write = $write; + } + + /** + * Delegate unknown methods to the _write adapter. + * + * @param string $method + * @param array $args + */ + public function __call($method, $args) + { + return call_user_func_array(array($this->_write, $method), $args); + } + + /** + * Returns the human-readable name of the adapter. Use mixed case - one + * can always use downcase if needed. + * + * @return string + */ + public function adapterName() + { + return 'SplitRead'; + } + + /** + * Does this adapter support migrations? + * + * @return boolean + */ + public function supportsMigrations() + { + return $this->_write->supportsMigrations(); + } + + /** + * Does this adapter support using DISTINCT within COUNT? This is +true+ + * for all adapters except sqlite. + * + * @return boolean + */ + public function supportsCountDistinct() + { + return $this->_read->supportsCountDistinct(); + } + + /** + * Should primary key values be selected from their corresponding + * sequence before the insert statement? If true, next_sequence_value + * is called before each insert to set the record's primary key. + * This is false for all adapters but Firebird. + * + * @return boolean + */ + public function prefetchPrimaryKey($tableName = null) + { + return $this->_write->prefetchPrimaryKey($tableName); + } + + /*########################################################################## + # Connection Management + ##########################################################################*/ + + /** + * Connect to the db. + * @TODO: Lazy connect? + * + */ + public function connect() + { + $this->_write->connect(); + $this->_read->connect(); + } + + /** + * Is the connection active? + * + * @return boolean + */ + public function isActive() + { + return ($this->_read->isActive() && $this->_write->isActive()); + } + + /** + * Reconnect to the db. + */ + public function reconnect() + { + $this->disconnect(); + $this->connect(); + } + + /** + * Disconnect from db. + */ + public function disconnect() + { + $this->_read->disconnect(); + $this->_write->disconnect(); + } + + /** + * Provides access to the underlying database connection. Useful for when + * you need to call a proprietary method such as postgresql's + * lo_* methods. + * + * @return resource + */ + public function rawConnection() + { + return $this->_write->rawConnection(); + } + + + /*########################################################################## + # Database Statements + ##########################################################################*/ + + /** + * Returns an array of records with the column names as keys, and + * column values as values. + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a query + * name. + * @param string $arg2 If $arg1 contains bound parameters, the query + * name. + * + * @return PDOStatement + * @throws Horde_Db_Exception + */ + public function select($sql, $arg1 = null, $arg2 = null) + { + return $this->_read->select($sql, $arg1, $arg2); + } + + /** + * Returns an array of record hashes with the column names as keys and + * column values as values. + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a query + * name. + * @param string $arg2 If $arg1 contains bound parameters, the query + * name. + * + * @return array + * @throws Horde_Db_Exception + */ + public function selectAll($sql, $arg1 = null, $arg2 = null) + { + return $this->_read->selectAll($sql, $arg1, $arg2); + } + + /** + * Returns a record hash with the column names as keys and column values + * as values. + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a query + * name. + * @param string $arg2 If $arg1 contains bound parameters, the query + * name. + * + * @return array + * @throws Horde_Db_Exception + */ + public function selectOne($sql, $arg1 = null, $arg2 = null) + { + return $this->_read->selectOne($sql, $arg1, $arg2); + } + + /** + * Returns a single value from a record + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a query + * name. + * @param string $arg2 If $arg1 contains bound parameters, the query + * name. + * + * @return string + * @throws Horde_Db_Exception + */ + public function selectValue($sql, $arg1 = null, $arg2 = null) + { + return $this->_read->selectValue($sql, $arg1, $arg2); + } + + /** + * Returns an array of the values of the first column in a select: + * selectValues("SELECT id FROM companies LIMIT 3") => [1,2,3] + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a query + * name. + * @param string $arg2 If $arg1 contains bound parameters, the query + * name. + * + * @return array + * @throws Horde_Db_Exception + */ + public function selectValues($sql, $arg1 = null, $arg2 = null) + { + return $this->_read->selectValues($sql, $arg1, $arg2); + } + + /** + * Returns an array where the keys are the first column of a select, and the + * values are the second column: + * + * selectAssoc("SELECT id, name FROM companies LIMIT 3") => [1 => 'Ford', 2 => 'GM', 3 => 'Chrysler'] + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a query + * name. + * @param string $arg2 If $arg1 contains bound parameters, the query + * name. + * + * @return array + * @throws Horde_Db_Exception + */ + public function selectAssoc($sql, $arg1 = null, $arg2 = null) + { + return $this->_read->selectAssoc($sql, $arg1, $arg2); + } + + /** + * Executes the SQL statement in the context of this connection. + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a query + * name. + * @param string $arg2 If $arg1 contains bound parameters, the query + * name. + * + * @return PDOStatement + * @throws Horde_Db_Exception + */ + public function execute($sql, $arg1 = null, $arg2 = null) + { + // Can't assume this will always be a read action, use _write. + return $this->_write->execute($sql, $arg1, $arg2); + } + + /** + * Returns the last auto-generated ID from the affected table. + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a + * query name. + * @param string $arg2 If $arg1 contains bound parameters, the + * query name. + * @param string $pk TODO + * @param integer $idValue TODO + * @param string $sequenceName TODO + * + * @return integer Last inserted ID. + * @throws Horde_Db_Exception + */ + public function insert($sql, $arg1 = null, $arg2 = null, $pk = null, + $idValue = null, $sequenceName = null) + { + return $this->_write->insert($sql, $arg1, $arg2, $pk, $idValue, $sequenceName); + } + + /** + * Executes the update statement and returns the number of rows affected. + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a query + * name. + * @param string $arg2 If $arg1 contains bound parameters, the query + * name. + * + * @return integer Number of rows affected. + * @throws Horde_Db_Exception + */ + public function update($sql, $arg1 = null, $arg2 = null) + { + return $this->_write->update($sql, $arg1, $arg2); + } + + /** + * Executes the delete statement and returns the number of rows affected. + * + * @param string $sql SQL statement. + * @param mixed $arg1 Either an array of bound parameters or a query + * name. + * @param string $arg2 If $arg1 contains bound parameters, the query + * name. + * + * @return integer Number of rows affected. + * @throws Horde_Db_Exception + */ + public function delete($sql, $arg1 = null, $arg2 = null) + { + return $this->_write->delete($sql, $arg1, $arg2); + } + + /** + * Check if a transaction has been started. + * + * @return boolean True if transaction has been started. + */ + public function transactionStarted() + { + return $this->_write->transactionStarted(); + } + /** + * Begins the transaction (and turns off auto-committing). + */ + public function beginDbTransaction() + { + return $this->_write->beginDbTransaction(); + } + + /** + * Commits the transaction (and turns on auto-committing). + */ + public function commitDbTransaction() + { + return $this->_write->commitDbTransaction(); + } + + /** + * Rolls back the transaction (and turns on auto-committing). Must be + * done if the transaction block raises an exception or returns false. + */ + public function rollbackDbTransaction() + { + return $this->_write->rollbackDbTransaction(); + } + + /** + * Appends +LIMIT+ and +OFFSET+ options to a SQL statement. + * + * @param string $sql SQL statement. + * @param array $options TODO + * + * @return string + */ + public function addLimitOffset($sql, $options) + { + return $this->_read->addLimitOffset($sql, $options); + } + + /** + * Appends a locking clause to an SQL statement. + * This method *modifies* the +sql+ parameter. + * + * # SELECT * FROM suppliers FOR UPDATE + * add_lock! 'SELECT * FROM suppliers', :lock => true + * add_lock! 'SELECT * FROM suppliers', :lock => ' FOR UPDATE' + * + * @param string &$sql SQL statment. + * @param array $options TODO. + */ + public function addLock(&$sql, array $options = array()) + { + $this->_write->addLock(&$sql, $options); + } + +} diff --git a/framework/Db/package.xml b/framework/Db/package.xml index d30857804..513858950 100644 --- a/framework/Db/package.xml +++ b/framework/Db/package.xml @@ -1,13 +1,9 @@ - + Db pear.horde.org Horde Database Libraries - Horde Database/SQL abstraction layer - + Horde Database/SQL abstraction layer Mike Naberezny mnaberez @@ -20,7 +16,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> chuck@horde.org yes - 2008-09-19 + 2010-10-22 + 0.1.0 0.1.0 @@ -30,11 +27,16 @@ http://pear.php.net/dtd/package-2.0.xsd"> beta BSD - * Add support for adding autoincrement to a column. + +* Add support for adding autoincrement to a column. * Initial release - + + + + + @@ -72,6 +74,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + @@ -84,6 +88,73 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -112,40 +183,94 @@ http://pear.php.net/dtd/package-2.0.xsd"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.1.0 + 0.1.0 + + + beta + beta + + 2010-10-22 + BSD + +* Add support for adding autoincrement to a column. + * Initial release + + + -- 2.11.0