2006-09-22 01:09:58 +04:00
< ? php
/*
* $Id $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL . For more information , see
* < http :// www . phpdoctrine . com >.
*/
/**
2006-11-11 22:32:34 +03:00
* Doctrine_Db
2006-09-22 01:09:58 +04:00
* A thin layer on top of PDO
*
* @ author Konsta Vesterinen
* @ license LGPL
* @ package Doctrine
*/
2006-11-11 22:32:34 +03:00
class Doctrine_Db2 implements Countable , IteratorAggregate , Doctrine_Adapter_Interface {
2006-11-08 15:11:55 +03:00
/**
* error constants
*/
const ERR = - 1 ;
const ERR_SYNTAX = - 2 ;
const ERR_CONSTRAINT = - 3 ;
const ERR_NOT_FOUND = - 4 ;
const ERR_ALREADY_EXISTS = - 5 ;
const ERR_UNSUPPORTED = - 6 ;
const ERR_MISMATCH = - 7 ;
const ERR_INVALID = - 8 ;
const ERR_NOT_CAPABLE = - 9 ;
const ERR_TRUNCATED = - 10 ;
const ERR_INVALID_NUMBER = - 11 ;
const ERR_INVALID_DATE = - 12 ;
const ERR_DIVZERO = - 13 ;
const ERR_NODBSELECTED = - 14 ;
const ERR_CANNOT_CREATE = - 15 ;
const ERR_CANNOT_DELETE = - 16 ;
const ERR_CANNOT_DROP = - 17 ;
const ERR_NOSUCHTABLE = - 18 ;
const ERR_NOSUCHFIELD = - 19 ;
const ERR_NEED_MORE_DATA = - 20 ;
const ERR_NOT_LOCKED = - 21 ;
const ERR_VALUE_COUNT_ON_ROW = - 22 ;
const ERR_INVALID_DSN = - 23 ;
const ERR_CONNECT_FAILED = - 24 ;
const ERR_EXTENSION_NOT_FOUND = - 25 ;
const ERR_NOSUCHDB = - 26 ;
const ERR_ACCESS_VIOLATION = - 27 ;
const ERR_CANNOT_REPLACE = - 28 ;
const ERR_CONSTRAINT_NOT_NULL = - 29 ;
const ERR_DEADLOCK = - 30 ;
const ERR_CANNOT_ALTER = - 31 ;
const ERR_MANAGER = - 32 ;
const ERR_MANAGER_PARSE = - 33 ;
const ERR_LOADMODULE = - 34 ;
const ERR_INSUFFICIENT_DATA = - 35 ;
2006-09-22 01:09:58 +04:00
/**
* @ var array $instances all the instances of this class
*/
protected static $instances = array ();
/**
* @ var array $isConnected whether or not a connection has been established
*/
protected $isConnected = false ;
2006-09-23 02:16:12 +04:00
/**
2006-09-22 01:09:58 +04:00
* @ var PDO $dbh the database handler
*/
2006-09-23 02:16:12 +04:00
protected $dbh ;
/**
2006-11-08 13:18:15 +03:00
* @ var array $options
*/
protected $options = array ( 'dsn' => null ,
'username' => null ,
'password' => null ,
);
/**
2006-11-11 22:32:34 +03:00
* @ var Doctrine_Db_EventListener_Interface | Doctrine_Overloadable $listener
2006-11-08 13:18:15 +03:00
* listener for listening events
2006-09-23 02:16:12 +04:00
*/
protected $listener ;
2006-11-05 22:24:28 +03:00
/**
* @ var integer $querySequence
*/
protected $querySequence = 0 ;
private static $driverMap = array ( 'oracle' => 'oci8' ,
'postgres' => 'pgsql' ,
'oci' => 'oci8' ,
'sqlite2' => 'sqlite' ,
'sqlite3' => 'sqlite' );
2006-09-23 02:16:12 +04:00
2006-09-22 01:09:58 +04:00
/**
* constructor
*
* @ param string $dsn data source name
2006-11-08 13:18:15 +03:00
* @ param string $user database username
* @ param string $pass database password
2006-09-22 01:09:58 +04:00
*/
2006-11-08 13:18:15 +03:00
public function __construct ( $dsn , $user , $pass ) {
if ( ! isset ( $user )) {
$a = self :: parseDSN ( $dsn );
extract ( $a );
}
$this -> options [ 'dsn' ] = $dsn ;
$this -> options [ 'username' ] = $user ;
$this -> options [ 'password' ] = $pass ;
2006-11-11 22:32:34 +03:00
$this -> listener = new Doctrine_Db_EventListener ();
2006-09-22 01:09:58 +04:00
}
2006-11-05 22:24:28 +03:00
2006-11-08 02:12:05 +03:00
public function nextQuerySequence () {
return ++ $this -> querySequence ;
}
2006-11-05 22:24:28 +03:00
/**
* getQuerySequence
*/
public function getQuerySequence () {
return $this -> querySequence ;
}
2006-09-23 14:44:39 +04:00
/**
* getDBH
*/
public function getDBH () {
return $this -> dbh ;
}
2006-11-08 13:18:15 +03:00
public function getOption ( $name ) {
if ( ! array_key_exists ( $name , $this -> options ))
throw new Doctrine_Db_Exception ( 'Unknown option ' . $name );
return $this -> options [ $name ];
2006-09-22 01:09:58 +04:00
}
2006-09-23 14:44:39 +04:00
/**
* addListener
*
2006-11-11 22:32:34 +03:00
* @ param Doctrine_Db_EventListener_Interface | Doctrine_Overloadable $listener
* @ return Doctrine_Db
2006-09-23 14:44:39 +04:00
*/
public function addListener ( $listener , $name = null ) {
2006-11-11 13:54:55 +03:00
if ( ! ( $this -> listener instanceof Doctrine_Db_EventListener_Chain ))
$this -> listener = new Doctrine_Db_EventListener_Chain ();
2006-09-23 14:44:39 +04:00
$this -> listener -> add ( $listener , $name );
return $this ;
}
/**
* getListener
*
2006-11-11 22:32:34 +03:00
* @ return Doctrine_Db_EventListener_Interface | Doctrine_Overloadable
2006-09-23 14:44:39 +04:00
*/
public function getListener () {
return $this -> listener ;
}
/**
* setListener
*
2006-11-11 22:32:34 +03:00
* @ param Doctrine_Db_EventListener_Interface | Doctrine_Overloadable $listener
* @ return Doctrine_Db
2006-09-23 14:44:39 +04:00
*/
public function setListener ( $listener ) {
2006-11-11 13:54:55 +03:00
if ( ! ( $listener instanceof Doctrine_Db_EventListener_Interface ) &&
2006-09-23 14:44:39 +04:00
! ( $listener instanceof Doctrine_Overloadable ))
2006-11-11 22:32:34 +03:00
throw new Doctrine_Db_Exception ( " Couldn't set eventlistener for database handler. EventListeners should implement either Doctrine_Db_EventListener_Interface or Doctrine_Overloadable " );
2006-09-23 14:44:39 +04:00
$this -> listener = $listener ;
return $this ;
}
2006-09-22 01:09:58 +04:00
2006-09-23 14:44:39 +04:00
/**
2006-09-22 01:09:58 +04:00
* connect
* connects into database
*
* @ return boolean
*/
public function connect () {
2006-09-23 14:44:39 +04:00
if ( $this -> isConnected )
2006-09-22 01:09:58 +04:00
return false ;
2006-11-08 13:18:15 +03:00
$this -> dbh = new PDO ( $this -> options [ 'dsn' ], $this -> options [ 'username' ], $this -> options [ 'password' ]);
2006-09-22 01:09:58 +04:00
$this -> dbh -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION );
2006-11-11 22:32:34 +03:00
$this -> dbh -> setAttribute ( PDO :: ATTR_STATEMENT_CLASS , array ( " Doctrine_Db_Statement " , array ( $this )));
2006-09-27 14:55:02 +04:00
$this -> isConnected = true ;
2006-09-22 01:09:58 +04:00
return true ;
}
/**
* getConnection
*
2006-09-23 02:16:12 +04:00
* @ param string $dsn PEAR :: DB like DSN or PDO like DSN
* format for PEAR :: DB like DSN : schema :// user : password @ address / dbname
2006-09-22 01:09:58 +04:00
*
* @ return
*/
public static function getConnection ( $dsn = null , $username = null , $password = null ) {
2006-11-08 13:18:15 +03:00
return new self ( $dsn , $username , $password );
2006-09-22 01:09:58 +04:00
}
2006-11-08 13:18:15 +03:00
/**
2006-09-24 14:00:44 +04:00
* driverName
* converts a driver name like ( oracle ) to appropriate PDO
* driver name ( oci8 in the case of oracle )
*
* @ param string $name
* @ return string
*/
public static function driverName ( $name ) {
if ( isset ( self :: $driverMap [ $name ]))
return self :: $driverMap [ $name ];
return $name ;
2006-09-23 14:44:39 +04:00
}
/**
* parseDSN
*
* @ param string $dsn
* @ return array Parsed contents of DSN
*/
function parseDSN ( $dsn ) {
2006-09-24 14:00:44 +04:00
// silence any warnings
2006-09-23 14:44:39 +04:00
$parts = @ parse_url ( $dsn );
$names = array ( 'scheme' , 'host' , 'port' , 'user' , 'pass' , 'path' , 'query' , 'fragment' );
foreach ( $names as $name ) {
if ( ! isset ( $parts [ $name ]))
$parts [ $name ] = null ;
}
if ( count ( $parts ) == 0 || ! isset ( $parts [ 'scheme' ]))
2006-11-11 22:32:34 +03:00
throw new Doctrine_Db_Exception ( 'Empty data source name' );
2006-09-23 14:44:39 +04:00
$drivers = self :: getAvailableDrivers ();
2006-09-24 14:00:44 +04:00
$parts [ 'scheme' ] = self :: driverName ( $parts [ 'scheme' ]);
2006-09-23 14:44:39 +04:00
if ( ! in_array ( $parts [ 'scheme' ], $drivers ))
2006-11-11 22:32:34 +03:00
throw new Doctrine_Db_Exception ( 'Driver ' . $parts [ 'scheme' ] . ' not availible or extension not loaded' );
2006-09-23 14:44:39 +04:00
switch ( $parts [ 'scheme' ]) {
case 'sqlite' :
if ( isset ( $parts [ 'host' ]) && $parts [ 'host' ] == ':memory' ) {
$parts [ 'database' ] = ':memory:' ;
$parts [ 'dsn' ] = 'sqlite::memory:' ;
}
break ;
case 'mysql' :
case 'informix' :
case 'oci8' :
case 'mssql' :
case 'firebird' :
case 'pgsql' :
case 'odbc' :
if ( ! isset ( $parts [ 'path' ]) || $parts [ 'path' ] == '/' )
2006-11-11 22:32:34 +03:00
throw new Doctrine_Db_Exception ( 'No database availible in data source name' );
2006-09-23 14:44:39 +04:00
if ( isset ( $parts [ 'path' ]))
$parts [ 'database' ] = substr ( $parts [ 'path' ], 1 );
if ( ! isset ( $parts [ 'host' ]))
2006-11-11 22:32:34 +03:00
throw new Doctrine_Db_Exception ( 'No hostname set in data source name' );
2006-09-23 14:44:39 +04:00
$parts [ 'dsn' ] = $parts [ " scheme " ] . " :host= " . $parts [ " host " ] . " ;dbname= " . $parts [ " database " ];
break ;
default :
2006-11-11 22:32:34 +03:00
throw new Doctrine_Db_Exception ( 'Unknown driver ' . $parts [ 'scheme' ]);
2006-09-23 14:44:39 +04:00
}
return $parts ;
}
2006-09-22 01:09:58 +04:00
/**
* clear
* clears all instances from the memory
*
* @ return void
*/
public static function clear () {
self :: $instances = array ();
}
/**
* errorCode
* Fetch the SQLSTATE associated with the last operation on the database handle
*
* @ return integer
*/
2006-09-23 02:16:12 +04:00
public function errorCode () {
2006-09-22 01:09:58 +04:00
return $this -> dbh -> errorCode ();
}
/**
* errorInfo
* Fetch extended error information associated with the last operation on the database handle
*
* @ return array
*/
public function errorInfo () {
return $this -> dbh -> errorInfo ();
}
/**
2006-09-23 02:16:12 +04:00
* prepare
2006-09-22 01:09:58 +04:00
*
* @ param string $statement
*/
2006-09-23 02:16:12 +04:00
public function prepare ( $statement ) {
2006-09-27 14:55:02 +04:00
$this -> connect ();
2006-11-08 02:12:05 +03:00
$event = new Doctrine_Db_Event ( $this , Doctrine_Db_Event :: PREPARE , $statement );
2006-09-23 14:44:39 +04:00
2006-11-08 02:12:05 +03:00
$this -> listener -> onPrePrepare ( $event );
2006-09-23 02:16:12 +04:00
$stmt = $this -> dbh -> prepare ( $statement );
2006-09-23 14:44:39 +04:00
2006-11-08 02:12:05 +03:00
$this -> listener -> onPrepare ( $event );
2006-11-05 22:24:28 +03:00
$this -> querySequence ++ ;
2006-09-23 02:16:12 +04:00
return $stmt ;
2006-09-22 01:09:58 +04:00
}
/**
* query
*
* @ param string $statement
2006-11-05 22:24:28 +03:00
* @ param array $params
2006-11-11 22:32:34 +03:00
* @ return Doctrine_Db_Statement | boolean
2006-09-22 01:09:58 +04:00
*/
2006-09-27 14:55:02 +04:00
public function query ( $statement , array $params = array ()) {
$this -> connect ();
2006-11-08 02:12:05 +03:00
$event = new Doctrine_Db_Event ( $this , Doctrine_Db_Event :: QUERY , $statement );
$this -> listener -> onPreQuery ( $event );
if ( ! empty ( $params ))
2006-09-27 14:55:02 +04:00
$stmt = $this -> dbh -> query ( $statement ) -> execute ( $params );
else
$stmt = $this -> dbh -> query ( $statement );
2006-09-23 02:16:12 +04:00
2006-11-08 02:12:05 +03:00
$this -> listener -> onQuery ( $event );
2006-11-05 22:24:28 +03:00
$this -> querySequence ++ ;
2006-09-22 01:09:58 +04:00
return $stmt ;
}
/**
* quote
* quotes a string for use in a query
*
* @ param string $input
* @ return string
*/
public function quote ( $input ) {
$this -> connect ();
2006-09-23 02:16:12 +04:00
2006-09-22 01:09:58 +04:00
return $this -> dbh -> quote ( $input );
}
/**
* exec
* executes an SQL statement and returns the number of affected rows
*
* @ param string $statement
* @ return integer
*/
public function exec ( $statement ) {
2006-09-27 14:55:02 +04:00
$this -> connect ();
2006-09-23 14:44:39 +04:00
$args = func_get_args ();
2006-11-08 02:12:05 +03:00
$event = new Doctrine_Db_Event ( $this , Doctrine_Db_Event :: EXEC , $statement );
2006-09-23 14:44:39 +04:00
2006-11-08 02:12:05 +03:00
$this -> listener -> onPreExec ( $event );
2006-09-23 02:16:12 +04:00
$rows = $this -> dbh -> exec ( $statement );
2006-11-08 02:12:05 +03:00
$this -> listener -> onExec ( $event );
2006-09-23 02:16:12 +04:00
return $rows ;
2006-09-22 01:09:58 +04:00
}
2006-09-26 01:08:02 +04:00
/**
* fetchAll
2006-09-27 14:55:02 +04:00
*
* @ return array
2006-09-26 01:08:02 +04:00
*/
2006-09-27 14:55:02 +04:00
public function fetchAll ( $statement , array $params = array ()) {
return $this -> query ( $statement , $params ) -> fetchAll ( PDO :: FETCH_ASSOC );
}
public function fetchOne ( $statement , array $params = array ()) {
return current ( $this -> query ( $statement , $params ) -> fetch ( PDO :: FETCH_NUM ));
}
public function fetchRow ( $statement , array $params = array ()) {
return $this -> query ( $statement , $params ) -> fetch ( PDO :: FETCH_ASSOC );
}
public function fetchArray ( $statement , array $params = array ()) {
return $this -> query ( $statement , $params ) -> fetch ( PDO :: FETCH_NUM );
}
public function fetchColumn ( $statement , array $params = array ()) {
return $this -> query ( $statement , $params ) -> fetchAll ( PDO :: FETCH_COLUMN );
}
public function fetchAssoc ( $statement , array $params = array ()) {
return $this -> query ( $statement , $params ) -> fetchAll ( PDO :: FETCH_ASSOC );
}
public function fetchBoth ( $statement , array $params = array ()) {
return $this -> query ( $statement , $params ) -> fetchAll ( PDO :: FETCH_BOTH );
2006-09-26 01:08:02 +04:00
}
2006-09-22 01:09:58 +04:00
/**
* lastInsertId
*
2006-09-27 14:55:02 +04:00
* @ return integer
2006-09-22 01:09:58 +04:00
*/
public function lastInsertId () {
$this -> connect ();
return $this -> dbh -> lastInsertId ();
}
/**
* begins a transaction
*
* @ return boolean
*/
public function beginTransaction () {
2006-11-08 02:12:05 +03:00
$event = new Doctrine_Db_Event ( $this , Doctrine_Db_Event :: BEGIN );
$this -> listener -> onPreBeginTransaction ( $event );
2006-09-22 01:09:58 +04:00
2006-09-23 02:16:12 +04:00
$return = $this -> dbh -> beginTransaction ();
2006-11-08 02:12:05 +03:00
$this -> listener -> onBeginTransaction ( $event );
2006-09-23 02:16:12 +04:00
return $return ;
2006-09-22 01:09:58 +04:00
}
/**
* commits a transaction
*
* @ return boolean
*/
public function commit () {
2006-11-08 02:12:05 +03:00
$event = new Doctrine_Db_Event ( $this , Doctrine_Db_Event :: COMMIT );
$this -> listener -> onPreCommit ( $event );
2006-09-23 02:16:12 +04:00
$return = $this -> dbh -> commit ();
2006-11-08 02:12:05 +03:00
$this -> listener -> onCommit ( $event );
2006-09-23 02:16:12 +04:00
return $return ;
2006-09-22 01:09:58 +04:00
}
/**
* rollBack
*
* @ return boolean
*/
public function rollBack () {
$this -> connect ();
2006-11-08 02:12:05 +03:00
$event = new Doctrine_Db_Event ( $this , Doctrine_Db_Event :: ROLLBACK );
$this -> listener -> onPreRollback ( $event );
2006-09-22 01:09:58 +04:00
$this -> dbh -> rollBack ();
2006-11-08 02:12:05 +03:00
$this -> listener -> onRollback ( $event );
2006-09-22 01:09:58 +04:00
}
/**
* getAttribute
* retrieves a database connection attribute
*
* @ param integer $attribute
* @ return mixed
*/
public function getAttribute ( $attribute ) {
$this -> connect ();
2006-11-08 13:18:15 +03:00
return $this -> dbh -> getAttribute ( $attribute );
2006-09-22 01:09:58 +04:00
}
/**
* returns an array of available PDO drivers
*/
public static function getAvailableDrivers () {
2006-09-23 01:20:21 +04:00
return PDO :: getAvailableDrivers ();
2006-09-22 01:09:58 +04:00
}
/**
* setAttribute
* sets an attribute
*
* @ param integer $attribute
* @ param mixed $value
* @ return boolean
*/
public function setAttribute ( $attribute , $value ) {
$this -> connect ();
$this -> dbh -> setAttribute ( $attribute , $value );
}
/**
* getIterator
*
* @ return ArrayIterator
*/
public function getIterator () {
2006-11-11 22:32:34 +03:00
if ( $this -> listener instanceof Doctrine_Db_Profiler )
2006-11-05 22:24:28 +03:00
return $this -> listener ;
2006-09-22 01:09:58 +04:00
}
/**
* count
* returns the number of executed queries
*
* @ return integer
*/
public function count () {
2006-11-05 22:24:28 +03:00
return $this -> querySequence ;
2006-11-08 13:18:15 +03:00
}
2006-09-22 01:09:58 +04:00
}