Commit e704cd0f authored by romanb's avatar romanb

Continued refactorings. Started to refactor the DBAL layer.

parent a7699974
...@@ -29,7 +29,8 @@ ...@@ -29,7 +29,8 @@
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Remove.
*/ */
class Doctrine_Adapter class Doctrine_Adapter
{ {
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
#namespace Doctrine::Common::Cache;
/** /**
* Doctrine_Cache_Apc * Doctrine_Cache_Apc
...@@ -28,7 +30,8 @@ ...@@ -28,7 +30,8 @@
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Rename to ApcCache
*/ */
class Doctrine_Cache_Apc extends Doctrine_Cache_Driver class Doctrine_Cache_Apc extends Doctrine_Cache_Driver
{ {
......
...@@ -1837,6 +1837,20 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable ...@@ -1837,6 +1837,20 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
{ {
$this->_generatorType = $type; $this->_generatorType = $type;
} }
public function completeIdentifierMapping()
{
if ($this->getIdGeneratorType() == self::GENERATOR_TYPE_AUTO) {
$platform = $this->_em->getConnection()->getDatabasePlatform();
if ($platform->prefersSequences()) {
$this->_generatorType = self::GENERATOR_TYPE_SEQUENCE;
} else if ($platform->prefersIdentityColumns()) {
$this->_generatorType = self::GENERATOR_TYPE_IDENTITY;
} else {
$this->_generatorType = self::GENERATOR_TYPE_TABLE;
}
}
}
/** /**
* *
......
...@@ -295,28 +295,7 @@ class Doctrine_ClassMetadata_Factory ...@@ -295,28 +295,7 @@ class Doctrine_ClassMetadata_Factory
// are unnecessary as we can easily replace them with polymorphic calls on // are unnecessary as we can easily replace them with polymorphic calls on
// the connection (or another) object. We just need to decide where to put // the connection (or another) object. We just need to decide where to put
// the id generation types. // the id generation types.
if ($class->getIdGeneratorType() == Doctrine_ClassMetadata::GENERATOR_TYPE_AUTO) { $class->completeIdentifierMapping();
switch (strtolower($this->_em->getConnection()->getDriverName())) {
case 'mysql':
// pick IDENTITY
$class->setIdGeneratorType(Doctrine_ClassMetadata::GENERATOR_TYPE_IDENTITY);
break;
case 'oracle':
//pick SEQUENCE
break;
case 'postgres':
//pick SEQUENCE
break;
case 'firebird':
//pick what?
break;
case 'mssql':
//pick what?
default:
throw new Doctrine_Exception("Encountered unknown database driver: "
. $this->_em->getConnection()->getDriverName());
}
}
} }
} }
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#namespace Doctrine::DBAL::Connections; #namespace Doctrine::DBAL::Connections;
#use Doctrine::Common::Configuration; #use Doctrine::Common::Configuration;
#use Doctrine::Common::EventManager;
#use Doctrine::DBAL::Exceptions::ConnectionException;
/** /**
* A thin connection wrapper on top of PDO. * A thin connection wrapper on top of PDO.
...@@ -40,7 +42,6 @@ ...@@ -40,7 +42,6 @@
* Doctrine_Connection provides many convenience methods such as fetchAll(), fetchOne() etc. * Doctrine_Connection provides many convenience methods such as fetchAll(), fetchOne() etc.
* *
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
...@@ -62,9 +63,9 @@ ...@@ -62,9 +63,9 @@
* 'masterConnectionResolver' => new MyMasterConnectionResolver() * 'masterConnectionResolver' => new MyMasterConnectionResolver()
* *
* Doctrine::DBAL could ship with a simple standard broker that uses a primitive * Doctrine::DBAL could ship with a simple standard broker that uses a primitive
* round-robin approach to distribution. User can provide its own resolvers. * round-robin approach to distribution. User can provide its own brokers.
*/ */
abstract class Doctrine_Connection implements Countable abstract class Doctrine_Connection
{ {
/** /**
* The PDO database handle. * The PDO database handle.
...@@ -87,13 +88,6 @@ abstract class Doctrine_Connection implements Countable ...@@ -87,13 +88,6 @@ abstract class Doctrine_Connection implements Countable
*/ */
protected $_eventManager; protected $_eventManager;
/**
* The attributes.
*
* @var array
*/
protected $_attributes = array();
/** /**
* Name of the connection * Name of the connection
* *
...@@ -111,7 +105,7 @@ abstract class Doctrine_Connection implements Countable ...@@ -111,7 +105,7 @@ abstract class Doctrine_Connection implements Countable
/** /**
* Whether or not a connection has been established. * Whether or not a connection has been established.
* *
* @var boolean $isConnected * @var boolean
*/ */
protected $_isConnected = false; protected $_isConnected = false;
...@@ -122,22 +116,6 @@ abstract class Doctrine_Connection implements Countable ...@@ -122,22 +116,6 @@ abstract class Doctrine_Connection implements Countable
*/ */
protected $_quoteIdentifiers; protected $_quoteIdentifiers;
/**
* The connection properties.
*
* @var array $properties
*/
protected $properties = array(
'sql_comments' => array(
array('start' => '--', 'end' => "\n", 'escape' => false),
array('start' => '/*', 'end' => '*/', 'escape' => false)),
'identifier_quoting' => array('start' => '"', 'end' => '"','escape' => '"'),
'string_quoting' => array('start' => "'", 'end' => "'", 'escape' => false,
'escape_pattern' => false),
'wildcards' => array('%', '_'),
'varchar_max_length' => 255,
);
/** /**
* @var array $serverInfo * @var array $serverInfo
*/ */
...@@ -173,7 +151,14 @@ abstract class Doctrine_Connection implements Countable ...@@ -173,7 +151,14 @@ abstract class Doctrine_Connection implements Countable
* *
* @var Doctrine::DBAL::Platforms::DatabasePlatform * @var Doctrine::DBAL::Platforms::DatabasePlatform
*/ */
protected $_databasePlatform; protected $_platform;
/**
* Enter description here...
*
* @var Doctrine::DBAL::Transactions::Transaction
*/
protected $_transaction;
/** /**
* Constructor. * Constructor.
...@@ -237,18 +222,14 @@ abstract class Doctrine_Connection implements Countable ...@@ -237,18 +222,14 @@ abstract class Doctrine_Connection implements Countable
} }
/** /**
* Enter description here... * Gets the DatabasePlatform for the connection.
* *
* @param unknown_type $name * @return Doctrine::DBAL::Platforms::DatabasePlatform
* @return unknown
* @todo Remove. Move properties to DatabasePlatform.
*/ */
public function getProperty($name) public function getDatabasePlatform()
{ {
if ( ! isset($this->properties[$name])) { throw new Doctrine_Connection_Exception("No DatabasePlatform available "
throw Doctrine_Connection_Exception::unknownProperty($name); . "for connection " . get_class($this));
}
return $this->properties[$name];
} }
/** /**
...@@ -827,7 +808,8 @@ abstract class Doctrine_Connection implements Countable ...@@ -827,7 +808,8 @@ abstract class Doctrine_Connection implements Countable
} }
/** /**
* execute * Executes an SQL SELECT query with the given parameters.
*
* @param string $query sql query * @param string $query sql query
* @param array $params query parameters * @param array $params query parameters
* *
...@@ -860,11 +842,13 @@ abstract class Doctrine_Connection implements Countable ...@@ -860,11 +842,13 @@ abstract class Doctrine_Connection implements Countable
} }
/** /**
* exec * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters.
*
* @param string $query sql query * @param string $query sql query
* @param array $params query parameters * @param array $params query parameters
* *
* @return PDOStatement|Doctrine_Adapter_Statement * @return PDOStatement|Doctrine_Adapter_Statement
* @todo Rename to executeUpdate().
*/ */
public function exec($query, array $params = array()) { public function exec($query, array $params = array()) {
$this->connect(); $this->connect();
...@@ -891,30 +875,6 @@ abstract class Doctrine_Connection implements Countable ...@@ -891,30 +875,6 @@ abstract class Doctrine_Connection implements Countable
$this->rethrowException($e, $this); $this->rethrowException($e, $this);
} }
} }
/**
*
*
* @return string
* @todo Rather orm stuff
*/
public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false)
{
return $query;
}
/**
* Creates dbms specific LIMIT/OFFSET SQL for the subqueries that are used in the
* context of the limit-subquery algorithm.
*
* @return string
* @todo Rather ORM stuff
*/
public function modifyLimitSubquery(Doctrine_Table $rootTable, $query, $limit = false,
$offset = false, $isManip = false)
{
return $this->modifyLimitQuery($query, $limit, $offset, $isManip);
}
/** /**
* Wraps the given exception into a driver-specific exception and rethrows it. * Wraps the given exception into a driver-specific exception and rethrows it.
...@@ -945,7 +905,7 @@ abstract class Doctrine_Connection implements Countable ...@@ -945,7 +905,7 @@ abstract class Doctrine_Connection implements Countable
* @return integer * @return integer
* @todo Better name: getQueryCount() * @todo Better name: getQueryCount()
*/ */
public function count() public function getQueryCount()
{ {
return $this->_queryCount; return $this->_queryCount;
} }
...@@ -1030,7 +990,7 @@ abstract class Doctrine_Connection implements Countable ...@@ -1030,7 +990,7 @@ abstract class Doctrine_Connection implements Countable
*/ */
public function beginTransaction($savepoint = null) public function beginTransaction($savepoint = null)
{ {
return $this->transaction->beginTransaction($savepoint); return $this->_transaction->beginTransaction($savepoint);
} }
/** /**
...@@ -1260,14 +1220,6 @@ abstract class Doctrine_Connection implements Countable ...@@ -1260,14 +1220,6 @@ abstract class Doctrine_Connection implements Countable
return false; return false;
} }
} }
public function getFormatter()
{
if ( ! $this->modules['formatter']) {
$this->modules['formatter'] = new Doctrine_Formatter($this);
}
return $this->modules['formatter'];
}
public function getSequenceManager() public function getSequenceManager()
{ {
...@@ -1277,16 +1229,4 @@ abstract class Doctrine_Connection implements Countable ...@@ -1277,16 +1229,4 @@ abstract class Doctrine_Connection implements Countable
} }
return $this->modules['sequence']; return $this->modules['sequence'];
} }
/**
* Gets the default (preferred) Id generation strategy of the database platform.
*
* @todo Sure, the id generator types are more ORM functionality but they're
* still kind of dbal related. Maybe we need another set of classes (DatabasePlatform?)
* but im not so sure...
*/
/*abstract*/ public function getDefaultIdGeneratorType()
{
}
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Connection');
/** /**
* Doctrine_Connection_Db2 * Doctrine_Connection_Db2
* *
......
...@@ -45,38 +45,9 @@ class Doctrine_Connection_Firebird extends Doctrine_Connection ...@@ -45,38 +45,9 @@ class Doctrine_Connection_Firebird extends Doctrine_Connection
* @param Doctrine_Manager $manager * @param Doctrine_Manager $manager
* @param PDO $pdo database handle * @param PDO $pdo database handle
*/ */
public function __construct(Doctrine_Manager $manager, $adapter) public function __construct(array $params)
{ {
parent::__construct($params);
$this->supported = array(
'sequences' => true,
'indexes' => true,
'affected_rows' => true,
'summary_functions' => true,
'order_by_text' => true,
'transactions' => true,
'savepoints' => true,
'current_id' => true,
'limit_queries' => 'emulated',
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => true,
'identifier_quoting' => false,
'pattern_escaping' => true
);
// initialize all driver options
/**
$this->options['DBA_username'] = false;
$this->options['DBA_password'] = false;
$this->options['database_path'] = '';
$this->options['database_extension'] = '.gdb';
$this->options['server_version'] = '';
*/
parent::__construct($manager, $adapter);
} }
/** /**
...@@ -92,23 +63,4 @@ class Doctrine_Connection_Firebird extends Doctrine_Connection ...@@ -92,23 +63,4 @@ class Doctrine_Connection_Firebird extends Doctrine_Connection
$this->exec($query); $this->exec($query);
} }
/**
* Adds an driver-specific LIMIT clause to the query
*
* @param string $query query to modify
* @param integer $limit limit the number of rows
* @param integer $offset start reading from given offset
* @return string modified query
*/
public function modifyLimitQuery($query, $limit, $offset)
{
if ( ! $offset) {
$offset = 0;
}
if ($limit > 0) {
$query = preg_replace('/^([\s(])*SELECT(?!\s*FIRST\s*\d+)/i',
"SELECT FIRST $limit SKIP $offset", $query);
}
return $query;
}
} }
\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Connection');
/** /**
* Doctrine_Connection_Mysql * Doctrine_Connection_Mysql
* *
......
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @version $Revision$ * @version $Revision$
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @todo Remove.
*/ */
class Doctrine_Connection_Mock extends Doctrine_Connection_Common class Doctrine_Connection_Mock extends Doctrine_Connection_Common
{ {
...@@ -48,7 +49,12 @@ class Doctrine_Connection_Mock extends Doctrine_Connection_Common ...@@ -48,7 +49,12 @@ class Doctrine_Connection_Mock extends Doctrine_Connection_Common
*/ */
public function __construct() public function __construct()
{ {
}
public function getDatabasePlatform()
{
return new Doctrine_DatabasePlatform_MySqlPlatform();
} }
public function quote($input, $type = null) public function quote($input, $type = null)
......
...@@ -44,28 +44,9 @@ class Doctrine_Connection_Mssql extends Doctrine_Connection ...@@ -44,28 +44,9 @@ class Doctrine_Connection_Mssql extends Doctrine_Connection
* @param Doctrine_Manager $manager * @param Doctrine_Manager $manager
* @param PDO $pdo database handle * @param PDO $pdo database handle
*/ */
public function __construct(Doctrine_Manager $manager, $adapter) public function __construct(array $params)
{ {
// initialize all driver options parent::__construct($params);
$this->supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'transactions' => true,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => 'emulated',
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => 'emulated',
);
parent::__construct($manager, $adapter);
} }
/** /**
...@@ -97,52 +78,6 @@ class Doctrine_Connection_Mssql extends Doctrine_Connection ...@@ -97,52 +78,6 @@ class Doctrine_Connection_Mssql extends Doctrine_Connection
return '[' . str_replace(']', ']]', $identifier) . ']'; return '[' . str_replace(']', ']]', $identifier) . ']';
} }
/**
* Adds an adapter-specific LIMIT clause to the SELECT statement.
* [ borrowed from Zend Framework ]
*
* @param string $query
* @param mixed $limit
* @param mixed $offset
* @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
* @return string
*/
public function modifyLimitQuery($query, $limit, $offset, $isManip = false)
{
if ($limit > 0) {
$count = intval($limit);
$offset = intval($offset);
if ($offset < 0) {
throw new Doctrine_Connection_Exception("LIMIT argument offset=$offset is not valid");
}
$orderby = stristr($query, 'ORDER BY');
if ($orderby !== false) {
$sort = (stripos($orderby, 'desc') !== false) ? 'desc' : 'asc';
$order = str_ireplace('ORDER BY', '', $orderby);
$order = trim(preg_replace('/ASC|DESC/i', '', $order));
}
$query = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . ($count+$offset) . ' ', $query);
$query = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $query . ') AS inner_tbl';
if ($orderby !== false) {
$query .= ' ORDER BY ' . $order . ' ';
$query .= (stripos($sort, 'asc') !== false) ? 'DESC' : 'ASC';
}
$query .= ') AS outer_tbl';
if ($orderby !== false) {
$query .= ' ORDER BY ' . $order . ' ' . $sort;
}
return $query;
}
return $query;
}
/** /**
* return version information about the server * return version information about the server
* *
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
/** /**
* Doctrine_Connection_Mysql * Doctrine_Connection_Mysql
* *
* @package Doctrine
* @subpackage Connection
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
...@@ -49,47 +47,7 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common ...@@ -49,47 +47,7 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common
* @param PDO|Doctrine_Adapter $adapter database handler * @param PDO|Doctrine_Adapter $adapter database handler
*/ */
public function __construct(array $params) public function __construct(array $params)
{ {
$this->supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'transactions' => true,
'savepoints' => false,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => true,
'LOBs' => true,
'replace' => true,
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => 'emulated',
'identifier_quoting' => true,
'pattern_escaping' => true
);
$this->properties['string_quoting'] = array(
'start' => "'",
'end' => "'",
'escape' => '\\',
'escape_pattern' => '\\');
$this->properties['identifier_quoting'] = array(
'start' => '`',
'end' => '`',
'escape' => '`');
$this->properties['sql_comments'] = array(
array('start' => '-- ', 'end' => "\n", 'escape' => false),
array('start' => '#', 'end' => "\n", 'escape' => false),
array('start' => '/*', 'end' => '*/', 'escape' => false),
);
$this->properties['varchar_max_length'] = 255;
parent::__construct($params); parent::__construct($params);
} }
...@@ -232,5 +190,18 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common ...@@ -232,5 +190,18 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common
} }
return $dsn; return $dsn;
}
/**
* Gets the DatabasePlatform for the connection.
*
* @return Doctrine::DBAL::Platforms::MySqlPlatform
*/
public function getDatabasePlatform()
{
if ( ! $this->_platform) {
$this->_platform = new Doctrine_DatabasePlatform_MySqlPlatform();
}
return $this->_platform;
} }
} }
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
/** /**
* Doctrine_Connection_Oracle * Doctrine_Connection_Oracle
* *
* @package Doctrine
* @subpackage Connection
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
...@@ -37,38 +35,9 @@ class Doctrine_Connection_Oracle extends Doctrine_Connection ...@@ -37,38 +35,9 @@ class Doctrine_Connection_Oracle extends Doctrine_Connection
*/ */
protected $driverName = 'Oracle'; protected $driverName = 'Oracle';
public function __construct(Doctrine_Manager $manager, $adapter) public function __construct(array $params)
{ {
$this->supported = array( parent::__construct($params);
'sequences' => true,
'indexes' => true,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => true,
'affected_rows' => true,
'transactions' => true,
'savepoints' => true,
'limit_queries' => true,
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => false, // implementation is broken
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => true,
'identifier_quoting' => true,
'pattern_escaping' => true,
);
/**
$this->options['DBA_username'] = false;
$this->options['DBA_password'] = false;
$this->options['database_name_prefix'] = false;
$this->options['emulate_database'] = true;
$this->options['default_tablespace'] = false;
$this->options['default_text_field_length'] = 2000;
$this->options['result_prefetching'] = false;
*/
parent::__construct($manager, $adapter);
} }
/** /**
...@@ -79,60 +48,4 @@ class Doctrine_Connection_Oracle extends Doctrine_Connection ...@@ -79,60 +48,4 @@ class Doctrine_Connection_Oracle extends Doctrine_Connection
{ {
$this->exec('ALTER SESSION SET NLS_DATE_FORMAT = "' . $format . '"'); $this->exec('ALTER SESSION SET NLS_DATE_FORMAT = "' . $format . '"');
} }
/**
* Adds an driver-specific LIMIT clause to the query
*
* @param string $query query to modify
* @param integer $limit limit the number of rows
* @param integer $offset start reading from given offset
* @return string the modified query
*/
public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false)
{
return $this->_createLimitSubquery($query, $limit, $offset);
}
private function _createLimitSubquery($query, $limit, $offset, $column = null)
{
$limit = (int) $limit;
$offset = (int) $offset;
if (preg_match('/^\s*SELECT/i', $query)) {
if ( ! preg_match('/\sFROM\s/i', $query)) {
$query .= " FROM dual";
}
if ($limit > 0) {
$max = $offset + $limit;
$column = $column === null ? '*' : $column;
if ($offset > 0) {
$min = $offset + 1;
$query = 'SELECT b.'.$column.' FROM ('.
'SELECT a.*, ROWNUM AS doctrine_rownum FROM ('
. $query . ') a '.
') b '.
'WHERE doctrine_rownum BETWEEN ' . $min . ' AND ' . $max;
} else {
$query = 'SELECT a.'.$column.' FROM (' . $query .') a WHERE ROWNUM <= ' . $max;
}
}
}
return $query;
}
/**
* Creates the SQL for Oracle that can be used in the subquery for the limit-subquery
* algorithm.
*/
public function modifyLimitSubquery(Doctrine_ClassMetadata $rootClass, $query, $limit = false,
$offset = false, $isManip = false)
{
// NOTE: no composite key support
$columnNames = $rootClass->getIdentifierColumnNames();
if (count($columnNames) > 1) {
throw new Doctrine_Connection_Exception("Composite keys in LIMIT queries are "
. "currently not supported.");
}
$column = $columnNames[0];
return $this->_createLimitSubquery($query, $limit, $offset, $column);
}
} }
\ No newline at end of file
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
/** /**
* PgsqlConnection * PgsqlConnection
* *
* @package Doctrine
* @subpackage Connection
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
...@@ -46,39 +44,9 @@ class Doctrine_Connection_Pgsql extends Doctrine_Connection_Common ...@@ -46,39 +44,9 @@ class Doctrine_Connection_Pgsql extends Doctrine_Connection_Common
* @param Doctrine_Manager $manager * @param Doctrine_Manager $manager
* @param PDO $pdo database handle * @param PDO $pdo database handle
*/ */
public function __construct(Doctrine_Manager $manager, $adapter) public function __construct(array $params)
{ {
// initialize all driver options parent::__construct($params);
$this->supported = array(
'sequences' => true,
'indexes' => true,
'affected_rows' => true,
'summary_functions' => true,
'order_by_text' => true,
'transactions' => true,
'savepoints' => true,
'current_id' => true,
'limit_queries' => true,
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => 'emulated',
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => true,
'identifier_quoting' => true,
'pattern_escaping' => true,
);
$this->properties['string_quoting'] = array('start' => "'",
'end' => "'",
'escape' => "'",
'escape_pattern' => '\\');
$this->properties['identifier_quoting'] = array('start' => '"',
'end' => '"',
'escape' => '"');
parent::__construct($manager, $adapter);
} }
/** /**
...@@ -120,43 +88,6 @@ class Doctrine_Connection_Pgsql extends Doctrine_Connection_Common ...@@ -120,43 +88,6 @@ class Doctrine_Connection_Pgsql extends Doctrine_Connection_Common
return $item; return $item;
} }
/**
* Changes a query string for various DBMS specific reasons
*
* @param string $query query to modify
* @param integer $limit limit the number of rows
* @param integer $offset start reading from given offset
* @param boolean $isManip if the query is a DML query
* @return string modified query
*/
public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false)
{
if ($limit > 0) {
$query = rtrim($query);
if (substr($query, -1) == ';') {
$query = substr($query, 0, -1);
}
if ($isManip) {
$manip = preg_replace('/^(DELETE FROM|UPDATE).*$/', '\\1', $query);
$from = $match[2];
$where = $match[3];
$query = $manip . ' ' . $from . ' WHERE ctid=(SELECT ctid FROM '
. $from . ' ' . $where . ' LIMIT ' . $limit . ')';
} else {
if ( ! empty($limit)) {
$query .= ' LIMIT ' . $limit;
}
if ( ! empty($offset)) {
$query .= ' OFFSET ' . $offset;
}
}
}
return $query;
}
/** /**
* return version information about the server * return version information about the server
* *
......
...@@ -47,30 +47,8 @@ class Doctrine_Connection_Sqlite extends Doctrine_Connection_Common ...@@ -47,30 +47,8 @@ class Doctrine_Connection_Sqlite extends Doctrine_Connection_Common
* @param PDO $pdo database handle * @param PDO $pdo database handle
*/ */
public function __construct(array $params) public function __construct(array $params)
{ {
$this->supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => true,
'LOBs' => true,
'replace' => true,
'transactions' => true,
'savepoints' => false,
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => false, // not implemented
'prepared_statements' => 'emulated',
'identifier_quoting' => true,
'pattern_escaping' => false,
);
parent::__construct($params); parent::__construct($params);
if ($this->_isConnected) { if ($this->_isConnected) {
$this->_pdo->sqliteCreateFunction('mod', array('Doctrine_Expression_Sqlite', 'modImpl'), 2); $this->_pdo->sqliteCreateFunction('mod', array('Doctrine_Expression_Sqlite', 'modImpl'), 2);
$this->_pdo->sqliteCreateFunction('md5', 'md5', 1); $this->_pdo->sqliteCreateFunction('md5', 'md5', 1);
......
...@@ -28,191 +28,10 @@ ...@@ -28,191 +28,10 @@
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @version $Revision$ * @version $Revision$
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @todo Remove
*/ */
class Doctrine_DataDict_Firebird extends Doctrine_DataDict class Doctrine_DataDict_Firebird extends Doctrine_DataDict
{ {
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
*/
public function getNativeDeclaration($field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'varchar':
case 'string':
case 'array':
case 'object':
case 'char':
case 'text':
case 'gzip':
$length = !empty($field['length'])
? $field['length'] : 16777215; // TODO: $this->conn->options['default_text_field_length'];
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? 'CHAR('.$length.')' : 'VARCHAR('.$length.')';
case 'clob':
return 'BLOB SUB_TYPE 1';
case 'blob':
return 'BLOB SUB_TYPE 0';
case 'integer':
case 'enum':
case 'int':
return 'INT';
case 'boolean':
return 'SMALLINT';
case 'date':
return 'DATE';
case 'time':
return 'TIME';
case 'timestamp':
return 'TIMESTAMP';
case 'float':
return 'DOUBLE PRECISION';
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'DECIMAL('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a Doctrine datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
*/
public function getPortableDeclaration($field)
{
$length = (isset($field['length']) && $field['length'] > 0) ? $field['length'] : null;
$type = array();
$unsigned = $fixed = null;
$dbType = strtolower($field['type']);
$field['field_sub_type'] = !empty($field['field_sub_type'])
? strtolower($field['field_sub_type']) : null;
if ( ! isset($field['name'])) {
$field['name'] = '';
}
switch ($dbType) {
case 'smallint':
case 'integer':
case 'int64':
//these may be 'numeric' or 'decimal'
if (isset($field['field_sub_type'])) {
$field['type'] = $field['field_sub_type'];
return $this->getPortableDeclaration($field);
}
case 'bigint':
case 'quad':
$type[] = 'integer';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
}
break;
case 'varchar':
$fixed = false;
case 'char':
case 'cstring':
$type[] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'date':
$type[] = 'date';
$length = null;
break;
case 'timestamp':
$type[] = 'timestamp';
$length = null;
break;
case 'time':
$type[] = 'time';
$length = null;
break;
case 'float':
case 'double':
case 'double precision':
case 'd_float':
$type[] = 'float';
break;
case 'decimal':
case 'numeric':
$type[] = 'decimal';
break;
case 'blob':
$type[] = ($field['field_sub_type'] == 'text') ? 'clob' : 'blob';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: '.$dbType);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
/**
* Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
* of a field declaration to be used in statements like CREATE TABLE.
*
* @param string $charset name of the charset
* @return string DBMS specific SQL code portion needed to set the CHARACTER SET
* of a field declaration.
*/
public function getCharsetFieldDeclaration($charset)
{
return 'CHARACTER SET ' . $charset;
}
/**
* Obtain DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration to be used in statements like CREATE TABLE.
*
* @param string $collation name of the collation
* @return string DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration.
*/
public function getCollationFieldDeclaration($collation)
{
return 'COLLATE ' . $collation;
}
} }
\ No newline at end of file
...@@ -31,80 +31,5 @@ ...@@ -31,80 +31,5 @@
*/ */
class Doctrine_DataDict_Informix extends Doctrine_DataDict class Doctrine_DataDict_Informix extends Doctrine_DataDict
{ {
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
*
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
*/
public function getNativeDeclaration($field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'char':
case 'varchar':
case 'array':
case 'object':
case 'string':
if (empty($field['length']) && array_key_exists('default', $field)) {
$field['length'] = $this->conn->varchar_max_length;
}
$length = ( ! empty($field['length'])) ? $field['length'] : false;
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR(255)')
: ($length ? 'VARCHAR('.$length.')' : 'NVARCHAR');
case 'clob':
return 'TEXT';
case 'blob':
return 'BLOB';
case 'integer':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 1) {
return 'SMALLINT';
} elseif ($length == 2) {
return 'SMALLINT';
} elseif ($length == 3 || $length == 4) {
return 'INTEGER';
} elseif ($length > 4) {
return 'DECIMAL(20)';
}
}
return 'INT';
case 'boolean':
return 'SMALLINT';
case 'date':
return 'DATE';
case 'time':
return 'DATETIME YEAR TO SECOND';
case 'timestamp':
return 'DATETIME';
case 'float':
return 'FLOAT';
case 'decimal':
return 'DECIMAL';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
} }
\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_DataDict');
/** /**
* @package Doctrine * @package Doctrine
* @subpackage DataDict * @subpackage DataDict
...@@ -29,166 +29,10 @@ Doctrine::autoload('Doctrine_DataDict'); ...@@ -29,166 +29,10 @@ Doctrine::autoload('Doctrine_DataDict');
* @author David Coallier <davidc@php.net> (PEAR MDB2 Mssql driver) * @author David Coallier <davidc@php.net> (PEAR MDB2 Mssql driver)
* @version $Revision$ * @version $Revision$
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @todo Remove
*/ */
class Doctrine_DataDict_Mssql extends Doctrine_DataDict class Doctrine_DataDict_Mssql extends Doctrine_DataDict
{ {
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
*
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
*/
public function getNativeDeclaration($field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'array':
case 'object':
case 'text':
case 'char':
case 'varchar':
case 'string':
case 'gzip':
$length = !empty($field['length'])
? $field['length'] : false;
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->options['default_text_field_length'].')')
: ($length ? 'VARCHAR('.$length.')' : 'TEXT');
case 'clob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 8000) {
return 'VARCHAR('.$length.')';
}
}
return 'TEXT';
case 'blob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 8000) {
return "VARBINARY($length)";
}
}
return 'IMAGE';
case 'integer':
case 'enum':
case 'int':
return 'INT';
case 'boolean':
return 'BIT';
case 'date':
return 'CHAR(' . strlen('YYYY-MM-DD') . ')';
case 'time':
return 'CHAR(' . strlen('HH:MM:SS') . ')';
case 'timestamp':
return 'CHAR(' . strlen('YYYY-MM-DD HH:MM:SS') . ')';
case 'float':
return 'FLOAT';
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'DECIMAL('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a MDB2 datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
*/
public function getPortableDeclaration($field)
{
$db_type = preg_replace('/[\d\(\)]/','', strtolower($field['type']) );
$length = (isset($field['length']) && $field['length'] > 0) ? $field['length'] : null;
$type = array();
// todo: unsigned handling seems to be missing
$unsigned = $fixed = null;
if ( ! isset($field['name']))
$field['name'] = '';
switch ($db_type) {
case 'bit':
$type[0] = 'boolean';
break;
case 'tinyint':
case 'smallint':
case 'int':
$type[0] = 'integer';
if ($length == 1) {
$type[] = 'boolean';
}
break;
case 'datetime':
$type[0] = 'timestamp';
break;
case 'float':
case 'real':
case 'numeric':
$type[0] = 'float';
break;
case 'decimal':
case 'money':
$type[0] = 'decimal';
break;
case 'text':
case 'varchar':
case 'ntext':
case 'nvarchar':
$fixed = false;
case 'char':
case 'nchar':
$type[0] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^[is|has]/', $field['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($db_type, 'text')) {
$type[] = 'clob';
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'image':
case 'varbinary':
$type[] = 'blob';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: '.$db_type);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
} }
...@@ -28,391 +28,9 @@ ...@@ -28,391 +28,9 @@
* @version $Revision$ * @version $Revision$
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @todo Remove
*/ */
class Doctrine_DataDict_Mysql extends Doctrine_DataDict class Doctrine_DataDict_Mysql extends Doctrine_DataDict
{ {
protected $keywords = array(
'ADD', 'ALL', 'ALTER',
'ANALYZE', 'AND', 'AS',
'ASC', 'ASENSITIVE', 'BEFORE',
'BETWEEN', 'BIGINT', 'BINARY',
'BLOB', 'BOTH', 'BY',
'CALL', 'CASCADE', 'CASE',
'CHANGE', 'CHAR', 'CHARACTER',
'CHECK', 'COLLATE', 'COLUMN',
'CONDITION', 'CONNECTION', 'CONSTRAINT',
'CONTINUE', 'CONVERT', 'CREATE',
'CROSS', 'CURRENT_DATE', 'CURRENT_TIME',
'CURRENT_TIMESTAMP', 'CURRENT_USER', 'CURSOR',
'DATABASE', 'DATABASES', 'DAY_HOUR',
'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND',
'DEC', 'DECIMAL', 'DECLARE',
'DEFAULT', 'DELAYED', 'DELETE',
'DESC', 'DESCRIBE', 'DETERMINISTIC',
'DISTINCT', 'DISTINCTROW', 'DIV',
'DOUBLE', 'DROP', 'DUAL',
'EACH', 'ELSE', 'ELSEIF',
'ENCLOSED', 'ESCAPED', 'EXISTS',
'EXIT', 'EXPLAIN', 'FALSE',
'FETCH', 'FLOAT', 'FLOAT4',
'FLOAT8', 'FOR', 'FORCE',
'FOREIGN', 'FROM', 'FULLTEXT',
'GRANT', 'GROUP', 'HAVING',
'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE',
'HOUR_SECOND', 'IF', 'IGNORE',
'IN', 'INDEX', 'INFILE',
'INNER', 'INOUT', 'INSENSITIVE',
'INSERT', 'INT', 'INT1',
'INT2', 'INT3', 'INT4',
'INT8', 'INTEGER', 'INTERVAL',
'INTO', 'IS', 'ITERATE',
'JOIN', 'KEY', 'KEYS',
'KILL', 'LEADING', 'LEAVE',
'LEFT', 'LIKE', 'LIMIT',
'LINES', 'LOAD', 'LOCALTIME',
'LOCALTIMESTAMP', 'LOCK', 'LONG',
'LONGBLOB', 'LONGTEXT', 'LOOP',
'LOW_PRIORITY', 'MATCH', 'MEDIUMBLOB',
'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT',
'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'MOD',
'MODIFIES', 'NATURAL', 'NOT',
'NO_WRITE_TO_BINLOG', 'NULL', 'NUMERIC',
'ON', 'OPTIMIZE', 'OPTION',
'OPTIONALLY', 'OR', 'ORDER',
'OUT', 'OUTER', 'OUTFILE',
'PRECISION', 'PRIMARY', 'PROCEDURE',
'PURGE', 'RAID0', 'READ',
'READS', 'REAL', 'REFERENCES',
'REGEXP', 'RELEASE', 'RENAME',
'REPEAT', 'REPLACE', 'REQUIRE',
'RESTRICT', 'RETURN', 'REVOKE',
'RIGHT', 'RLIKE', 'SCHEMA',
'SCHEMAS', 'SECOND_MICROSECOND', 'SELECT',
'SENSITIVE', 'SEPARATOR', 'SET',
'SHOW', 'SMALLINT', 'SONAME',
'SPATIAL', 'SPECIFIC', 'SQL',
'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING',
'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_SMALL_RESULT',
'SSL', 'STARTING', 'STRAIGHT_JOIN',
'TABLE', 'TERMINATED', 'THEN',
'TINYBLOB', 'TINYINT', 'TINYTEXT',
'TO', 'TRAILING', 'TRIGGER',
'TRUE', 'UNDO', 'UNION',
'UNIQUE', 'UNLOCK', 'UNSIGNED',
'UPDATE', 'USAGE', 'USE',
'USING', 'UTC_DATE', 'UTC_TIME',
'UTC_TIMESTAMP', 'VALUES', 'VARBINARY',
'VARCHAR', 'VARCHARACTER', 'VARYING',
'WHEN', 'WHERE', 'WHILE',
'WITH', 'WRITE', 'X509',
'XOR', 'YEAR_MONTH', 'ZEROFILL'
);
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
*
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
*/
public function getNativeDeclaration($field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'char':
$length = ( ! empty($field['length'])) ? $field['length'] : false;
return $length ? 'CHAR('.$length.')' : 'CHAR(255)';
case 'varchar':
case 'array':
case 'object':
case 'string':
case 'gzip':
if ( ! isset($field['length'])) {
if (array_key_exists('default', $field)) {
$field['length'] = $this->conn->varchar_max_length;
} else {
$field['length'] = false;
}
}
$length = ($field['length'] <= $this->conn->varchar_max_length) ? $field['length'] : false;
$fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
: ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
case 'clob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYTEXT';
} elseif ($length <= 65532) {
return 'TEXT';
} elseif ($length <= 16777215) {
return 'MEDIUMTEXT';
}
}
return 'LONGTEXT';
case 'blob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYBLOB';
} elseif ($length <= 65532) {
return 'BLOB';
} elseif ($length <= 16777215) {
return 'MEDIUMBLOB';
}
}
return 'LONGBLOB';
case 'enum':
if ($this->conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
$values = array();
foreach ($field['values'] as $value) {
$values[] = $this->conn->quote($value, 'varchar');
}
return 'ENUM('.implode(', ', $values).')';
}
// fall back to integer
case 'integer':
case 'int':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 1) {
return 'TINYINT';
} elseif ($length == 2) {
return 'SMALLINT';
} elseif ($length == 3) {
return 'MEDIUMINT';
} elseif ($length == 4) {
return 'INT';
} elseif ($length > 4) {
return 'BIGINT';
}
}
return 'INT';
case 'boolean':
return 'TINYINT(1)';
case 'date':
return 'DATE';
case 'time':
return 'TIME';
case 'timestamp':
return 'DATETIME';
case 'float':
case 'double':
return 'DOUBLE';
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'DECIMAL('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a Doctrine datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
*/
public function getPortableDeclaration(array $field)
{
$dbType = strtolower($field['type']);
$dbType = strtok($dbType, '(), ');
if ($dbType == 'national') {
$dbType = strtok('(), ');
}
if (isset($field['length'])) {
$length = $field['length'];
$decimal = '';
} else {
$length = strtok('(), ');
$decimal = strtok('(), ');
}
$type = array();
$unsigned = $fixed = null;
if ( ! isset($field['name'])) {
$field['name'] = '';
}
$values = null;
switch ($dbType) {
case 'tinyint':
$type[] = 'integer';
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 1;
break;
case 'smallint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 2;
break;
case 'mediumint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 3;
break;
case 'int':
case 'integer':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 4;
break;
case 'bigint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 8;
break;
case 'tinytext':
case 'mediumtext':
case 'longtext':
case 'text':
case 'text':
case 'varchar':
$fixed = false;
case 'string':
case 'char':
$type[] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($dbType, 'text')) {
$type[] = 'clob';
if ($decimal == 'binary') {
$type[] = 'blob';
}
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'enum':
$type[] = 'enum';
preg_match_all('/\'((?:\'\'|[^\'])*)\'/', $field['type'], $matches);
$length = 0;
$fixed = false;
if (is_array($matches)) {
foreach ($matches[1] as &$value) {
$value = str_replace('\'\'', '\'', $value);
$length = max($length, strlen($value));
}
if ($length == '1' && count($matches[1]) == 2) {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
} else {
$values = $matches[1];
}
}
$type[] = 'integer';
break;
case 'set':
$fixed = false;
$type[] = 'text';
$type[] = 'integer';
break;
case 'date':
$type[] = 'date';
$length = null;
break;
case 'datetime':
case 'timestamp':
$type[] = 'timestamp';
$length = null;
break;
case 'time':
$type[] = 'time';
$length = null;
break;
case 'float':
case 'double':
case 'real':
$type[] = 'float';
$unsigned = preg_match('/ unsigned/i', $field['type']);
break;
case 'unknown':
case 'decimal':
case 'numeric':
$type[] = 'decimal';
$unsigned = preg_match('/ unsigned/i', $field['type']);
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
$type[] = 'blob';
$length = null;
break;
case 'year':
$type[] = 'integer';
$type[] = 'date';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: ' . $dbType);
}
$length = ((int) $length == 0) ? null : (int) $length;
if ($values === null) {
return array('type' => $type, 'length' => $length, 'unsigned' => $unsigned, 'fixed' => $fixed);
} else {
return array('type' => $type, 'length' => $length, 'unsigned' => $unsigned, 'fixed' => $fixed, 'values' => $values);
}
}
/**
* Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
* of a field declaration to be used in statements like CREATE TABLE.
*
* @param string $charset name of the charset
* @return string DBMS specific SQL code portion needed to set the CHARACTER SET
* of a field declaration.
*/
public function getCharsetFieldDeclaration($charset)
{
return 'CHARACTER SET ' . $charset;
}
/**
* Obtain DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration to be used in statements like CREATE TABLE.
*
* @param string $collation name of the collation
* @return string DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration.
*/
public function getCollationFieldDeclaration($collation)
{
return 'COLLATE ' . $collation;
}
} }
...@@ -26,174 +26,10 @@ ...@@ -26,174 +26,10 @@
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @version $Revision$ * @version $Revision$
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @todo Remove
*/ */
class Doctrine_DataDict_Oracle extends Doctrine_DataDict class Doctrine_DataDict_Oracle extends Doctrine_DataDict
{ {
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
*/
public function getNativeDeclaration(array $field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'string':
case 'array':
case 'object':
case 'gzip':
case 'char':
case 'varchar':
$length = !empty($field['length'])
? $field['length'] : 16777215; // TODO: $this->conn->options['default_text_field_length'];
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? 'CHAR('.$length.')' : 'VARCHAR2('.$length.')';
case 'clob':
return 'CLOB';
case 'blob':
return 'BLOB';
case 'integer':
case 'enum':
case 'int':
if ( ! empty($field['length'])) {
return 'NUMBER('.$field['length'].')';
}
return 'INT';
case 'boolean':
return 'NUMBER(1)';
case 'date':
case 'time':
case 'timestamp':
return 'DATE';
case 'float':
case 'double':
return 'NUMBER';
case 'decimal':
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'NUMBER(*,'.$scale.')';
default:
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a doctrine datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
* @throws Doctrine_DataDict_Oracle_Exception
*/
public function getPortableDeclaration(array $field)
{
if ( ! isset($field['data_type'])) {
throw new Doctrine_DataDict_Exception('Native oracle definition must have a data_type key specified');
}
$dbType = strtolower($field['data_type']);
$type = array();
$length = $unsigned = $fixed = null;
if ( ! empty($field['data_length'])) {
$length = $field['data_length'];
}
if ( ! isset($field['column_name'])) {
$field['column_name'] = '';
}
switch ($dbType) {
case 'integer':
case 'pls_integer':
case 'binary_integer':
$type[] = 'integer';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['column_name'])) {
$type = array_reverse($type);
}
}
break;
case 'varchar':
case 'varchar2':
case 'nvarchar2':
$fixed = false;
case 'char':
case 'nchar':
$type[] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['column_name'])) {
$type = array_reverse($type);
}
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'date':
case 'timestamp':
$type[] = 'timestamp';
$length = null;
break;
case 'float':
$type[] = 'float';
break;
case 'number':
if ( ! empty($field['data_scale'])) {
$type[] = 'decimal';
} else {
$type[] = 'integer';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['column_name'])) {
$type = array_reverse($type);
}
}
}
break;
case 'long':
$type[] = 'string';
case 'clob':
case 'nclob':
$type[] = 'clob';
break;
case 'blob':
case 'raw':
case 'long raw':
case 'bfile':
$type[] = 'blob';
$length = null;
break;
case 'rowid':
case 'urowid':
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: ' . $dbType);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_DataDict');
/** /**
* @package Doctrine * @package Doctrine
* @subpackage DataDict * @subpackage DataDict
...@@ -29,547 +29,9 @@ Doctrine::autoload('Doctrine_DataDict'); ...@@ -29,547 +29,9 @@ Doctrine::autoload('Doctrine_DataDict');
* @version $Revision$ * @version $Revision$
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @todo Remove
*/ */
class Doctrine_DataDict_Pgsql extends Doctrine_DataDict class Doctrine_DataDict_Pgsql extends Doctrine_DataDict
{ {
/**
* @param array $reservedKeyWords an array of reserved keywords by pgsql
*/
protected static $reservedKeyWords = array(
'abort',
'absolute',
'access',
'action',
'add',
'after',
'aggregate',
'all',
'alter',
'analyse',
'analyze',
'and',
'any',
'as',
'asc',
'assertion',
'assignment',
'at',
'authorization',
'backward',
'before',
'begin',
'between',
'bigint',
'binary',
'bit',
'boolean',
'both',
'by',
'cache',
'called',
'cascade',
'case',
'cast',
'chain',
'char',
'character',
'characteristics',
'check',
'checkpoint',
'class',
'close',
'cluster',
'coalesce',
'collate',
'column',
'comment',
'commit',
'committed',
'constraint',
'constraints',
'conversion',
'convert',
'copy',
'create',
'createdb',
'createuser',
'cross',
'current_date',
'current_time',
'current_timestamp',
'current_user',
'cursor',
'cycle',
'database',
'day',
'deallocate',
'dec',
'decimal',
'declare',
'default',
'deferrable',
'deferred',
'definer',
'delete',
'delimiter',
'delimiters',
'desc',
'distinct',
'do',
'domain',
'double',
'drop',
'each',
'else',
'encoding',
'encrypted',
'end',
'escape',
'except',
'exclusive',
'execute',
'exists',
'explain',
'external',
'extract',
'false',
'fetch',
'float',
'for',
'force',
'foreign',
'forward',
'freeze',
'from',
'full',
'function',
'get',
'global',
'grant',
'group',
'handler',
'having',
'hour',
'ilike',
'immediate',
'immutable',
'implicit',
'in',
'increment',
'index',
'inherits',
'initially',
'inner',
'inout',
'input',
'insensitive',
'insert',
'instead',
'int',
'integer',
'intersect',
'interval',
'into',
'invoker',
'is',
'isnull',
'isolation',
'join',
'key',
'lancompiler',
'language',
'leading',
'left',
'level',
'like',
'limit',
'listen',
'load',
'local',
'localtime',
'localtimestamp',
'location',
'lock',
'match',
'maxvalue',
'minute',
'minvalue',
'mode',
'month',
'move',
'names',
'national',
'natural',
'nchar',
'new',
'next',
'no',
'nocreatedb',
'nocreateuser',
'none',
'not',
'nothing',
'notify',
'notnull',
'null',
'nullif',
'numeric',
'of',
'off',
'offset',
'oids',
'old',
'on',
'only',
'operator',
'option',
'or',
'order',
'out',
'outer',
'overlaps',
'overlay',
'owner',
'partial',
'password',
'path',
'pendant',
'placing',
'position',
'precision',
'prepare',
'primary',
'prior',
'privileges',
'procedural',
'procedure',
'read',
'real',
'recheck',
'references',
'reindex',
'relative',
'rename',
'replace',
'reset',
'restrict',
'returns',
'revoke',
'right',
'rollback',
'row',
'rule',
'schema',
'scroll',
'second',
'security',
'select',
'sequence',
'serializable',
'session',
'session_user',
'set',
'setof',
'share',
'show',
'similar',
'simple',
'smallint',
'some',
'stable',
'start',
'statement',
'statistics',
'stdin',
'stdout',
'storage',
'strict',
'substring',
'sysid',
'table',
'temp',
'template',
'temporary',
'then',
'time',
'timestamp',
'to',
'toast',
'trailing',
'transaction',
'treat',
'trigger',
'trim',
'true',
'truncate',
'trusted',
'type',
'unencrypted',
'union',
'unique',
'unknown',
'unlisten',
'until',
'update',
'usage',
'user',
'using',
'vacuum',
'valid',
'validator',
'values',
'varchar',
'varying',
'verbose',
'version',
'view',
'volatile',
'when',
'where',
'with',
'without',
'work',
'write',
'year',
'zone'
);
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
*
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
*/
public function getNativeDeclaration(array $field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'char':
case 'string':
case 'array':
case 'object':
case 'varchar':
case 'gzip':
// TODO: what is the maximum VARCHAR length in pgsql ?
$length = (isset($field['length']) && $field['length'] && $field['length'] < 10000) ? $field['length'] : null;
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR('.$this->conn->options['default_text_field_length'].')')
: ($length ? 'VARCHAR(' .$length . ')' : 'TEXT');
case 'clob':
return 'TEXT';
case 'blob':
return 'BYTEA';
case 'enum':
case 'integer':
case 'int':
if ( ! empty($field['autoincrement'])) {
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length > 4) {
return 'BIGSERIAL';
}
}
return 'SERIAL';
}
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 2) {
return 'SMALLINT';
} elseif ($length == 3 || $length == 4) {
return 'INT';
} elseif ($length > 4) {
return 'BIGINT';
}
}
return 'INT';
case 'boolean':
return 'BOOLEAN';
case 'date':
return 'DATE';
case 'time':
return 'TIME without time zone';
case 'timestamp':
return 'TIMESTAMP without time zone';
case 'float':
case 'double':
return 'FLOAT';
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'NUMERIC('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a portable Doctrine datatype and length
*
* @param array $field native field description
*
* @return array containing the various possible types, length, sign, fixed
*/
public function getPortableDeclaration(array $field)
{
$length = (isset($field['length'])) ? $field['length'] : null;
if ($length == '-1' && isset($field['atttypmod'])) {
$length = $field['atttypmod'] - 4;
}
if ((int)$length <= 0) {
$length = null;
}
$type = array();
$unsigned = $fixed = null;
if ( ! isset($field['name'])) {
$field['name'] = '';
}
$dbType = strtolower($field['type']);
switch ($dbType) {
case 'smallint':
case 'int2':
$type[] = 'integer';
$unsigned = false;
$length = 2;
if ($length == '2') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
}
break;
case 'int':
case 'int4':
case 'integer':
case 'serial':
case 'serial4':
$type[] = 'integer';
$unsigned = false;
$length = 4;
break;
case 'bigint':
case 'int8':
case 'bigserial':
case 'serial8':
$type[] = 'integer';
$unsigned = false;
$length = 8;
break;
case 'bool':
case 'boolean':
$type[] = 'boolean';
$length = 1;
break;
case 'text':
case 'varchar':
case 'interval':
case '_varchar':
$fixed = false;
case 'unknown':
case 'char':
case 'bpchar':
$type[] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($dbType, 'text')) {
$type[] = 'clob';
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'date':
$type[] = 'date';
$length = null;
break;
case 'datetime':
case 'timestamp':
case 'timestamptz':
$type[] = 'timestamp';
$length = null;
break;
case 'time':
$type[] = 'time';
$length = null;
break;
case 'float':
case 'float4':
case 'float8':
case 'double':
case 'double precision':
case 'real':
$type[] = 'float';
break;
case 'decimal':
case 'money':
case 'numeric':
$type[] = 'decimal';
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
case 'bytea':
$type[] = 'blob';
$length = null;
break;
case 'oid':
$type[] = 'blob';
$type[] = 'clob';
$length = null;
break;
case 'year':
$type[] = 'integer';
$type[] = 'date';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: '.$dbType);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
/**
* parseBoolean
* parses a literal boolean value and returns
* proper sql equivalent
*
* @param string $value boolean value to be parsed
* @return string parsed boolean value
*/
public function parseBoolean($value)
{
return $value;
}
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_DataDict');
/** /**
* @package Doctrine * @package Doctrine
* @subpackage DataDict * @subpackage DataDict
...@@ -27,218 +27,10 @@ Doctrine::autoload('Doctrine_DataDict'); ...@@ -27,218 +27,10 @@ Doctrine::autoload('Doctrine_DataDict');
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @version $Revision$ * @version $Revision$
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @todo Remove
*/ */
class Doctrine_DataDict_Sqlite extends Doctrine_DataDict class Doctrine_DataDict_Sqlite extends Doctrine_DataDict
{ {
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
* @author Lukas Smith (PEAR MDB2 library)
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
*/
public function getNativeDeclaration(array $field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'text':
case 'object':
case 'array':
case 'string':
case 'char':
case 'gzip':
case 'varchar':
$length = (isset($field['length']) && $field['length']) ? $field['length'] : null;
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->getAttribute(Doctrine::ATTR_DEFAULT_TEXTFLD_LENGTH).')')
: ($length ? 'VARCHAR('.$length.')' : 'TEXT');
case 'clob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYTEXT';
} elseif ($length <= 65535) {
return 'TEXT';
} elseif ($length <= 16777215) {
return 'MEDIUMTEXT';
}
}
return 'LONGTEXT';
case 'blob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYBLOB';
} elseif ($length <= 65535) {
return 'BLOB';
} elseif ($length <= 16777215) {
return 'MEDIUMBLOB';
}
}
return 'LONGBLOB';
case 'enum':
case 'integer':
case 'boolean':
case 'int':
return 'INTEGER';
case 'date':
return 'DATE';
case 'time':
return 'TIME';
case 'timestamp':
return 'DATETIME';
case 'float':
case 'double':
return 'DOUBLE';//($this->conn->options['fixed_float'] ? '('.
//($this->conn->options['fixed_float']+2).','.$this->conn->options['fixed_float'].')' : '');
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'DECIMAL('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to Doctrine datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
*/
public function getPortableDeclaration(array $field)
{
$dbType = strtolower($field['type']);
$length = (isset($field['length'])) ? $field['length'] : null;
$unsigned = (isset($field['unsigned'])) ? $field['unsigned'] : null;
$fixed = null;
$type = array();
if ( ! isset($field['name'])) {
$field['name'] = '';
}
switch ($dbType) {
case 'boolean':
$type[] = 'boolean';
break;
case 'tinyint':
$type[] = 'integer';
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 1;
break;
case 'smallint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 2;
break;
case 'mediumint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 3;
break;
case 'int':
case 'integer':
case 'serial':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 4;
break;
case 'bigint':
case 'bigserial':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 8;
break;
case 'clob':
case 'tinytext':
case 'mediumtext':
case 'longtext':
case 'text':
case 'varchar':
case 'varchar2':
$fixed = false;
case 'char':
$type[] = 'text';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($dbType, 'text')) {
$type[] = 'clob';
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'date':
$type[] = 'date';
$length = null;
break;
case 'datetime':
case 'timestamp':
$type[] = 'timestamp';
$length = null;
break;
case 'time':
$type[] = 'time';
$length = null;
break;
case 'float':
case 'double':
case 'real':
$type[] = 'float';
$length = null;
break;
case 'decimal':
case 'numeric':
$type[] = 'decimal';
$length = null;
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
$type[] = 'blob';
$length = null;
break;
case 'year':
$type[] = 'integer';
$type[] = 'date';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: '.$dbType);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
} }
<?php
#namespace Doctrine::DBAL::Platforms;
/**
* Base class for all DatabasePlatforms. The DatabasePlatforms are the central
* point of abstraction of platform-specific behaviors, features and SQL dialects.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class Doctrine_DatabasePlatform
{
/**
* An array containing all features this platform supports, keys representing feature
* names and values as one of the following (true, false, 'emulated').
*
* @var array
*/
protected $_supported = array();
/**
* Platform specific properties. Subclasses can override these in the
* constructor.
*
* @var array $properties
*/
protected $_properties = array(
'sql_comments' => array(
array(
'start' => '--',
'end' => "\n",
'escape' => false
),
array(
'start' => '/*',
'end' => '*/',
'escape' => false
)
),
'identifier_quoting' => array(
'start' => '"',
'end' => '"',
'escape' => '"'
),
'string_quoting' => array(
'start' => "'",
'end' => "'",
'escape' => false,
'escape_pattern' => false
),
'wildcards' => array('%', '_'),
'varchar_max_length' => 255,
);
public function __construct() {}
/**
* Checks whether a certain feature is supported.
*
* @param string $feature the name of the feature
* @return boolean whether or not this drivers supports given feature
*/
public function supports($feature)
{
return (isset($this->_supported[$feature]) &&
($this->_supported[$feature] === 'emulated' || $this->_supported[$feature]));
}
/**
* regexp
* returns the regular expression operator
*
* @return string
*/
public function getRegexpExpression()
{
throw new Doctrine_Expression_Exception('Regular expression operator is not supported by this database driver.');
}
/**
* Returns the average value of a column
*
* @param string $column the column to use
* @return string generated sql including an AVG aggregate function
*/
public function getAvgExpression($column)
{
$column = $this->getIdentifier($column);
return 'AVG(' . $column . ')';
}
/**
* Returns the number of rows (without a NULL value) of a column
*
* If a '*' is used instead of a column the number of selected rows
* is returned.
*
* @param string|integer $column the column to use
* @return string generated sql including a COUNT aggregate function
*/
public function getCountExpression($column)
{
$column = $this->getIdentifier($column);
return 'COUNT(' . $column . ')';
}
/**
* Returns the highest value of a column
*
* @param string $column the column to use
* @return string generated sql including a MAX aggregate function
*/
public function getMaxExpression($column)
{
$column = $this->getIdentifier($column);
return 'MAX(' . $column . ')';
}
/**
* Returns the lowest value of a column
*
* @param string $column the column to use
* @return string
*/
public function getMinExpression($column)
{
$column = $this->getIdentifier($column);
return 'MIN(' . $column . ')';
}
/**
* Returns the total sum of a column
*
* @param string $column the column to use
* @return string
*/
public function getSumExpression($column)
{
$column = $this->getIdentifier($column);
return 'SUM(' . $column . ')';
}
// scalar functions
/**
* Returns the md5 sum of a field.
*
* Note: Not SQL92, but common functionality
*
* @return string
*/
public function getMd5Expression($column)
{
$column = $this->getIdentifier($column);
return 'MD5(' . $column . ')';
}
/**
* Returns the length of a text field.
*
* @param string $expression1
* @param string $expression2
* @return string
*/
public function getLengthExpression($column)
{
$column = $this->getIdentifier($column);
return 'LENGTH(' . $column . ')';
}
/**
* Rounds a numeric field to the number of decimals specified.
*
* @param string $expression1
* @param string $expression2
* @return string
*/
public function getRoundExpression($column, $decimals = 0)
{
$column = $this->getIdentifier($column);
return 'ROUND(' . $column . ', ' . $decimals . ')';
}
/**
* Returns the remainder of the division operation
* $expression1 / $expression2.
*
* @param string $expression1
* @param string $expression2
* @return string
*/
public function getModExpression($expression1, $expression2)
{
$expression1 = $this->getIdentifier($expression1);
$expression2 = $this->getIdentifier($expression2);
return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
}
/**
* trim
* returns the string $str with leading and proceeding space characters removed
*
* @param string $str literal string or column name
* @return string
*/
public function getTrimExpression($str)
{
return 'TRIM(' . $str . ')';
}
/**
* rtrim
* returns the string $str with proceeding space characters removed
*
* @param string $str literal string or column name
* @return string
*/
public function getRtrimExpression($str)
{
return 'RTRIM(' . $str . ')';
}
/**
* ltrim
* returns the string $str with leading space characters removed
*
* @param string $str literal string or column name
* @return string
*/
public function getLtrimExpression($str)
{
return 'LTRIM(' . $str . ')';
}
/**
* upper
* Returns the string $str with all characters changed to
* uppercase according to the current character set mapping.
*
* @param string $str literal string or column name
* @return string
*/
public function getUpperExpression($str)
{
return 'UPPER(' . $str . ')';
}
/**
* lower
* Returns the string $str with all characters changed to
* lowercase according to the current character set mapping.
*
* @param string $str literal string or column name
* @return string
*/
public function getLowerExpression($str)
{
return 'LOWER(' . $str . ')';
}
/**
* locate
* returns the position of the first occurrence of substring $substr in string $str
*
* @param string $substr literal string to find
* @param string $str literal string
* @return integer
*/
public function getLocateExpression($str, $substr)
{
return 'LOCATE(' . $str . ', ' . $substr . ')';
}
/**
* Returns the current system date.
*
* @return string
*/
public function getNowExpression()
{
return 'NOW()';
}
/**
* soundex
* Returns a string to call a function to compute the
* soundex encoding of a string
*
* The string "?000" is returned if the argument is NULL.
*
* @param string $value
* @return string SQL soundex function with given parameter
*/
public function getSoundexExpression($value)
{
throw new Doctrine_Expression_Exception('SQL soundex function not supported by this driver.');
}
/**
* return string to call a function to get a substring inside an SQL statement
*
* Note: Not SQL92, but common functionality.
*
* SQLite only supports the 2 parameter variant of this function
*
* @param string $value an sql string literal or column name/alias
* @param integer $position where to start the substring portion
* @param integer $length the substring portion length
* @return string SQL substring function with given parameters
*/
public function getSubstringExpression($value, $from, $len = null)
{
$value = $this->getIdentifier($value);
if ($len === null)
return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
else {
$len = $this->getIdentifier($len);
return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $len . ')';
}
}
/**
* Returns a series of strings concatinated
*
* concat() accepts an arbitrary number of parameters. Each parameter
* must contain an expression
*
* @param string $arg1, $arg2 ... $argN strings that will be concatinated.
* @return string
*/
public function getConcatExpression()
{
$args = func_get_args();
return join(' || ' , $args);
}
/**
* Returns the SQL for a logical not.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $e = $q->expr;
* $q->select('*')->from('table')
* ->where($e->eq('id', $e->not('null'));
* </code>
*
* @return string a logical expression
*/
public function getNotExpression($expression)
{
$expression = $this->getIdentifier($expression);
return 'NOT(' . $expression . ')';
}
/**
* Returns the SQL to perform the same mathematical operation over an array
* of values or expressions.
*
* basicMath() accepts an arbitrary number of parameters. Each parameter
* must contain a value or an expression or an array with values or
* expressions.
*
* @param string $type the type of operation, can be '+', '-', '*' or '/'.
* @param string|array(string)
* @return string an expression
*/
private function getBasicMathExpression($type, array $args)
{
$elements = $this->getIdentifiers($args);
if (count($elements) < 1) {
return '';
}
if (count($elements) == 1) {
return $elements[0];
} else {
return '(' . implode(' ' . $type . ' ', $elements) . ')';
}
}
/**
* Returns the SQL to add values or expressions together.
*
* add() accepts an arbitrary number of parameters. Each parameter
* must contain a value or an expression or an array with values or
* expressions.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $e = $q->expr;
*
* $q->select('u.*')
* ->from('User u')
* ->where($e->eq($e->add('id', 2), 12));
* </code>
*
* @param string|array(string)
* @return string an expression
*/
public function getAddExpression(array $args)
{
return $this->basicMath('+', $args);
}
/**
* Returns the SQL to subtract values or expressions from eachother.
*
* subtract() accepts an arbitrary number of parameters. Each parameter
* must contain a value or an expression or an array with values or
* expressions.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $e = $q->expr;
*
* $q->select('u.*')
* ->from('User u')
* ->where($e->eq($e->sub('id', 2), 12));
* </code>
*
* @param string|array(string)
* @return string an expression
*/
public function getSubExpression(array $args)
{
return $this->basicMath('-', $args );
}
/**
* Returns the SQL to multiply values or expressions by eachother.
*
* multiply() accepts an arbitrary number of parameters. Each parameter
* must contain a value or an expression or an array with values or
* expressions.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $e = $q->expr;
*
* $q->select('u.*')
* ->from('User u')
* ->where($e->eq($e->mul('id', 2), 12));
* </code>
*
* @param string|array(string)
* @return string an expression
*/
public function getMulExpression(array $args)
{
return $this->basicMath('*', $args);
}
/**
* Returns the SQL to divide values or expressions by eachother.
*
* divide() accepts an arbitrary number of parameters. Each parameter
* must contain a value or an expression or an array with values or
* expressions.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $e = $q->expr;
*
* $q->select('u.*')
* ->from('User u')
* ->where($e->eq($e->div('id', 2), 12));
* </code>
*
* @param string|array(string)
* @return string an expression
*/
public function getDivExpression(array $args)
{
return $this->basicMath('/', $args);
}
/**
* Returns the SQL to check if two values are equal.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->eq('id', 1));
* </code>
*
* @param string $value1 logical expression to compare
* @param string $value2 logical expression to compare with
* @return string logical expression
*/
public function getEqExpression($value1, $value2)
{
$value1 = $this->getIdentifier($value1);
$value2 = $this->getIdentifier($value2);
return $value1 . ' = ' . $value2;
}
/**
* Returns the SQL to check if two values are unequal.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->neq('id', 1));
* </code>
*
* @param string $value1 logical expression to compare
* @param string $value2 logical expression to compare with
* @return string logical expression
*/
public function getNeqExpression($value1, $value2)
{
$value1 = $this->getIdentifier($value1);
$value2 = $this->getIdentifier($value2);
return $value1 . ' <> ' . $value2;
}
/**
* Returns the SQL to check if one value is greater than another value.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->gt('id', 1));
* </code>
*
* @param string $value1 logical expression to compare
* @param string $value2 logical expression to compare with
* @return string logical expression
*/
public function getGtExpression($value1, $value2)
{
$value1 = $this->getIdentifier($value1);
$value2 = $this->getIdentifier($value2);
return $value1 . ' > ' . $value2;
}
/**
* Returns the SQL to check if one value is greater than or equal to
* another value.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->gte('id', 1));
* </code>
*
* @param string $value1 logical expression to compare
* @param string $value2 logical expression to compare with
* @return string logical expression
*/
public function getGteExpression($value1, $value2)
{
$value1 = $this->getIdentifier($value1);
$value2 = $this->getIdentifier($value2);
return $value1 . ' >= ' . $value2;
}
/**
* Returns the SQL to check if one value is less than another value.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->lt('id', 1));
* </code>
*
* @param string $value1 logical expression to compare
* @param string $value2 logical expression to compare with
* @return string logical expression
*/
public function getLtExpression($value1, $value2)
{
$value1 = $this->getIdentifier($value1);
$value2 = $this->getIdentifier($value2);
return $value1 . ' < ' . $value2;
}
/**
* Returns the SQL to check if one value is less than or equal to
* another value.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->lte('id', 1));
* </code>
*
* @param string $value1 logical expression to compare
* @param string $value2 logical expression to compare with
* @return string logical expression
*/
public function getLteExpression($value1, $value2)
{
$value1 = $this->getIdentifier($value1);
$value2 = $this->getIdentifier($value2);
return $value1 . ' <= ' . $value2;
}
/**
* Returns the SQL to check if a value is one in a set of
* given values..
*
* in() accepts an arbitrary number of parameters. The first parameter
* must always specify the value that should be matched against. Successive
* must contain a logical expression or an array with logical expressions.
* These expressions will be matched against the first parameter.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->in( 'id', array(1,2,3)));
* </code>
*
* @param string $column the value that should be matched against
* @param string|array(string) values that will be matched against $column
* @return string logical expression
*/
public function getInExpression($column, $values)
{
if ( ! is_array($values)) {
$values = array($values);
}
$values = $this->getIdentifiers($values);
$column = $this->getIdentifier($column);
if (count($values) == 0) {
throw new Doctrine_Expression_Exception('Values array for IN operator should not be empty.');
}
return $column . ' IN (' . implode(', ', $values) . ')';
}
/**
* Returns SQL that checks if a expression is null.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->isNull('id'));
* </code>
*
* @param string $expression the expression that should be compared to null
* @return string logical expression
*/
public function getIsNullExpression($expression)
{
$expression = $this->getIdentifier($expression);
return $expression . ' IS NULL';
}
/**
* Returns SQL that checks if a expression is not null.
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->isNotNull('id'));
* </code>
*
* @param string $expression the expression that should be compared to null
* @return string logical expression
*/
public function getIsNotNullExpression($expression)
{
$expression = $this->getIdentifier($expression);
return $expression . ' IS NOT NULL';
}
/**
* Returns SQL that checks if an expression evaluates to a value between
* two values.
*
* The parameter $expression is checked if it is between $value1 and $value2.
*
* Note: There is a slight difference in the way BETWEEN works on some databases.
* http://www.w3schools.com/sql/sql_between.asp. If you want complete database
* independence you should avoid using between().
*
* Example:
* <code>
* $q = new Doctrine_Query();
* $q->select('u.*')
* ->from('User u')
* ->where($q->expr->between('id', 1, 5));
* </code>
*
* @param string $expression the value to compare to
* @param string $value1 the lower value to compare with
* @param string $value2 the higher value to compare with
* @return string logical expression
*/
public function getBetweenExpression($expression, $value1, $value2)
{
$expression = $this->getIdentifier($expression);
$value1 = $this->getIdentifier($value1);
$value2 = $this->getIdentifier($value2);
return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2;
}
/**
* Returns global unique identifier
*
* @return string to get global unique identifier
*/
public function getGuidExpression()
{
throw new Doctrine_Expression_Exception('method not implemented');
}
/**
* returns arcus cosine SQL string
*
* @return string
*/
public function getAcosExpression($value)
{
return 'ACOS(' . $value . ')';
}
/**
* sin
*
* @param string $value
* @return void
*/
public function getSinExpression($value)
{
return 'SIN(' . $value . ')';
}
/**
* pi
*
* @return void
*/
public function getPiExpression()
{
return 'PI()';
}
/**
* cos
*
* @param string $value
* @return void
* @author Jonathan H. Wage
*/
public function getCosExpression($value)
{
return 'COS(' . $value . ')';
}
/**
* build a pattern matching string
*
* EXPERIMENTAL
*
* WARNING: this function is experimental and may change signature at
* any time until labelled as non-experimental
*
* @access public
*
* @param array $pattern even keys are strings, odd are patterns (% and _)
* @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
* @param string $field optional field name that is being matched against
* (might be required when emulating ILIKE)
*
* @return string SQL pattern
*/
public function getMatchPatternExpression($pattern, $operator = null, $field = null)
{
throw new Doctrine_Expression_Exception("Method not implemented.");
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
*
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
*/
abstract public function getNativeDeclaration($field);
/**
* Maps a native array description of a field to a Doctrine datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
*/
abstract public function getPortableDeclaration(array $field);
/**
* Whether the platform prefers sequences for ID generation.
* Subclasses should override this method to return TRUE if they prefer sequences.
*
* @return boolean
*/
public function prefersSequences()
{
return false;
}
/**
* Whether the platform prefers identity columns (eg. autoincrement) for ID generation.
* Subclasses should override this method to return TRUE if they prefer identity columns.
*
* @return boolean
*/
public function prefersIdentityColumns()
{
return false;
}
/**
* Adds a LIMIT/OFFSET clause to the query.
* This default implementation writes the syntax "LIMIT x OFFSET y" to the
* query which is supported by MySql, PostgreSql and Sqlite.
* Any database platforms that do not support this syntax should override
* this implementation and provide their own.
*
* @param string $query The SQL string to write to / append to.
* @param mixed $limit
* @param mixed $offset
*/
public function writeLimitClause($query, $limit = false, $offset = false)
{
$limit = (int) $limit;
$offset = (int) $offset;
if ($limit && $offset) {
$query .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} elseif ($limit && ! $offset) {
$query .= ' LIMIT ' . $limit;
} elseif ( ! $limit && $offset) {
$query .= ' LIMIT 999999999999 OFFSET ' . $offset;
}
return $query;
}
/**
* Creates DBMS specific LIMIT/OFFSET SQL for the subqueries that are used in the
* context of the limit-subquery construction.
* This default implementation uses the normal LIMIT/OFFSET creation of the
* platform as provided by {@see modifyLimitQuery()}. This means LIMIT/OFFSET
* in subqueries don't get any special treatment. Most of the time this is not
* sufficient (eg. MySql does not allow LIMIT in subqueries) and the concrete
* platforms should provide their own implementation.
*
* @param string $query The SQL string to write to / append to.
* @return string
*/
public function writeLimitClauseInSubquery(Doctrine_ClassMetadata $rootClass, $query,
$limit = false, $offset = false)
{
return $this->modifyLimitQuery($query, $limit, $offset);
}
/**
* Enter description here...
*
* @param unknown_type $name
* @return unknown
* @todo Remove. Move properties to DatabasePlatform.
*/
public function getProperty($name)
{
if ( ! isset($this->_properties[$name])) {
throw Doctrine_Connection_Exception::unknownProperty($name);
}
return $this->_properties[$name];
}
}
?>
\ No newline at end of file
<?php
#namespace Doctrine::DBAL::Platforms;
/**
* Enter description here...
*
* @since 2.0
*/
class Doctrine_DatabasePlatform_FirebirdPlatform extends Doctrine_DatabasePlatform
{
/**
* Constructor.
*/
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => true,
'indexes' => true,
'affected_rows' => true,
'summary_functions' => true,
'order_by_text' => true,
'transactions' => true,
'savepoints' => true,
'current_id' => true,
'limit_queries' => 'emulated',
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => true,
'identifier_quoting' => false,
'pattern_escaping' => true
);
}
/**
* Adds an driver-specific LIMIT clause to the query
*
* @param string $query query to modify
* @param integer $limit limit the number of rows
* @param integer $offset start reading from given offset
* @return string modified query
* @override
*/
public function writeLimitClause($query, $limit, $offset)
{
if ( ! $offset) {
$offset = 0;
}
if ($limit > 0) {
$query = preg_replace('/^([\s(])*SELECT(?!\s*FIRST\s*\d+)/i',
"SELECT FIRST $limit SKIP $offset", $query);
}
return $query;
}
/**
* return string for internal table used when calling only a function
*
* @return string for internal table used when calling only a function
*/
public function getFunctionTableExpression()
{
return ' FROM RDB$DATABASE';
}
/**
* build string to define escape pattern string
*
* @return string define escape pattern
* @override
*/
public function getPatternEscapeStringExpression()
{
return " ESCAPE '". $this->_properties['escape_pattern'] ."'";
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
* @override
*/
public function getNativeDeclaration($field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'varchar':
case 'string':
case 'array':
case 'object':
case 'char':
case 'text':
case 'gzip':
$length = !empty($field['length'])
? $field['length'] : 16777215; // TODO: $this->conn->options['default_text_field_length'];
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? 'CHAR('.$length.')' : 'VARCHAR('.$length.')';
case 'clob':
return 'BLOB SUB_TYPE 1';
case 'blob':
return 'BLOB SUB_TYPE 0';
case 'integer':
case 'enum':
case 'int':
return 'INT';
case 'boolean':
return 'SMALLINT';
case 'date':
return 'DATE';
case 'time':
return 'TIME';
case 'timestamp':
return 'TIMESTAMP';
case 'float':
return 'DOUBLE PRECISION';
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'DECIMAL('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a Doctrine datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
* @override
*/
public function getPortableDeclaration($field)
{
$length = (isset($field['length']) && $field['length'] > 0) ? $field['length'] : null;
$type = array();
$unsigned = $fixed = null;
$dbType = strtolower($field['type']);
$field['field_sub_type'] = !empty($field['field_sub_type'])
? strtolower($field['field_sub_type']) : null;
if ( ! isset($field['name'])) {
$field['name'] = '';
}
switch ($dbType) {
case 'smallint':
case 'integer':
case 'int64':
//these may be 'numeric' or 'decimal'
if (isset($field['field_sub_type'])) {
$field['type'] = $field['field_sub_type'];
return $this->getPortableDeclaration($field);
}
case 'bigint':
case 'quad':
$type[] = 'integer';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
}
break;
case 'varchar':
$fixed = false;
case 'char':
case 'cstring':
$type[] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'date':
$type[] = 'date';
$length = null;
break;
case 'timestamp':
$type[] = 'timestamp';
$length = null;
break;
case 'time':
$type[] = 'time';
$length = null;
break;
case 'float':
case 'double':
case 'double precision':
case 'd_float':
$type[] = 'float';
break;
case 'decimal':
case 'numeric':
$type[] = 'decimal';
break;
case 'blob':
$type[] = ($field['field_sub_type'] == 'text') ? 'clob' : 'blob';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: '.$dbType);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
/**
* Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
* of a field declaration to be used in statements like CREATE TABLE.
*
* @param string $charset name of the charset
* @return string DBMS specific SQL code portion needed to set the CHARACTER SET
* of a field declaration.
*/
public function getCharsetFieldDeclaration($charset)
{
return 'CHARACTER SET ' . $charset;
}
/**
* Obtain DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration to be used in statements like CREATE TABLE.
*
* @param string $collation name of the collation
* @return string DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration.
*/
public function getCollationFieldDeclaration($collation)
{
return 'COLLATE ' . $collation;
}
}
?>
\ No newline at end of file
<?php
#namespace Doctrine::DBAL::Platforms;
/**
* Enter description here...
*
* @since 2.0
*/
class Doctrine_DatabasePlatform_InformixPlatform extends Doctrine_DatabasePlatform
{
public function __construct()
{
parent::__construct();
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
*
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
* @override
*/
public function getNativeDeclaration($field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'char':
case 'varchar':
case 'array':
case 'object':
case 'string':
if (empty($field['length']) && array_key_exists('default', $field)) {
$field['length'] = $this->conn->varchar_max_length;
}
$length = ( ! empty($field['length'])) ? $field['length'] : false;
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR(255)')
: ($length ? 'VARCHAR('.$length.')' : 'NVARCHAR');
case 'clob':
return 'TEXT';
case 'blob':
return 'BLOB';
case 'integer':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 1) {
return 'SMALLINT';
} elseif ($length == 2) {
return 'SMALLINT';
} elseif ($length == 3 || $length == 4) {
return 'INTEGER';
} elseif ($length > 4) {
return 'DECIMAL(20)';
}
}
return 'INT';
case 'boolean':
return 'SMALLINT';
case 'date':
return 'DATE';
case 'time':
return 'DATETIME YEAR TO SECOND';
case 'timestamp':
return 'DATETIME';
case 'float':
return 'FLOAT';
case 'decimal':
return 'DECIMAL';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
}
?>
\ No newline at end of file
<?php
class Doctrine_DatabasePlatform_MsSqlPlatform extends Doctrine_DatabasePlatform
{
/**
* the constructor
*/
public function __construct()
{
parent::__construct();
// initialize all driver options
$this->_supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'transactions' => true,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => 'emulated',
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => 'emulated',
);
}
/**
* Adds an adapter-specific LIMIT clause to the SELECT statement.
* [ borrowed from Zend Framework ]
*
* @param string $query
* @param mixed $limit
* @param mixed $offset
* @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
* @return string
* @override
*/
public function writeLimitClause($query, $limit, $offset)
{
if ($limit > 0) {
$count = intval($limit);
$offset = intval($offset);
if ($offset < 0) {
throw new Doctrine_Connection_Exception("LIMIT argument offset=$offset is not valid");
}
$orderby = stristr($query, 'ORDER BY');
if ($orderby !== false) {
$sort = (stripos($orderby, 'desc') !== false) ? 'desc' : 'asc';
$order = str_ireplace('ORDER BY', '', $orderby);
$order = trim(preg_replace('/ASC|DESC/i', '', $order));
}
$query = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . ($count+$offset) . ' ', $query);
$query = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $query . ') AS inner_tbl';
if ($orderby !== false) {
$query .= ' ORDER BY ' . $order . ' ';
$query .= (stripos($sort, 'asc') !== false) ? 'DESC' : 'ASC';
}
$query .= ') AS outer_tbl';
if ($orderby !== false) {
$query .= ' ORDER BY ' . $order . ' ' . $sort;
}
return $query;
}
return $query;
}
/**
* Return string to call a variable with the current timestamp inside an SQL statement
* There are three special variables for current date and time:
* - CURRENT_TIMESTAMP (date and time, TIMESTAMP type)
* - CURRENT_DATE (date, DATE type)
* - CURRENT_TIME (time, TIME type)
*
* @return string to call a variable with the current timestamp
* @override
*/
public function getNowExpression($type = 'timestamp')
{
switch ($type) {
case 'time':
case 'date':
case 'timestamp':
default:
return 'GETDATE()';
}
}
/**
* return string to call a function to get a substring inside an SQL statement
*
* @return string to call a function to get a substring
* @override
*/
public function getSubstringExpression($value, $position, $length = null)
{
if ( ! is_null($length)) {
return 'SUBSTRING(' . $value . ', ' . $position . ', ' . $length . ')';
}
return 'SUBSTRING(' . $value . ', ' . $position . ', LEN(' . $value . ') - ' . $position . ' + 1)';
}
/**
* Returns string to concatenate two or more string parameters
*
* @param string $arg1
* @param string $arg2
* @param string $values...
* @return string to concatenate two strings
* @override
*/
public function getConcatExpression()
{
$args = func_get_args();
return '(' . implode(' + ', $args) . ')';
}
/**
* Returns global unique identifier
*
* @return string to get global unique identifier
* @override
*/
public function getGuidExpression()
{
return 'NEWID()';
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
*
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
* @override
*/
public function getNativeDeclaration($field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'array':
case 'object':
case 'text':
case 'char':
case 'varchar':
case 'string':
case 'gzip':
$length = !empty($field['length'])
? $field['length'] : false;
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->options['default_text_field_length'].')')
: ($length ? 'VARCHAR('.$length.')' : 'TEXT');
case 'clob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 8000) {
return 'VARCHAR('.$length.')';
}
}
return 'TEXT';
case 'blob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 8000) {
return "VARBINARY($length)";
}
}
return 'IMAGE';
case 'integer':
case 'enum':
case 'int':
return 'INT';
case 'boolean':
return 'BIT';
case 'date':
return 'CHAR(' . strlen('YYYY-MM-DD') . ')';
case 'time':
return 'CHAR(' . strlen('HH:MM:SS') . ')';
case 'timestamp':
return 'CHAR(' . strlen('YYYY-MM-DD HH:MM:SS') . ')';
case 'float':
return 'FLOAT';
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'DECIMAL('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a MDB2 datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
* @override
*/
public function getPortableDeclaration($field)
{
$db_type = preg_replace('/[\d\(\)]/','', strtolower($field['type']) );
$length = (isset($field['length']) && $field['length'] > 0) ? $field['length'] : null;
$type = array();
// todo: unsigned handling seems to be missing
$unsigned = $fixed = null;
if ( ! isset($field['name']))
$field['name'] = '';
switch ($db_type) {
case 'bit':
$type[0] = 'boolean';
break;
case 'tinyint':
case 'smallint':
case 'int':
$type[0] = 'integer';
if ($length == 1) {
$type[] = 'boolean';
}
break;
case 'datetime':
$type[0] = 'timestamp';
break;
case 'float':
case 'real':
case 'numeric':
$type[0] = 'float';
break;
case 'decimal':
case 'money':
$type[0] = 'decimal';
break;
case 'text':
case 'varchar':
case 'ntext':
case 'nvarchar':
$fixed = false;
case 'char':
case 'nchar':
$type[0] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^[is|has]/', $field['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($db_type, 'text')) {
$type[] = 'clob';
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'image':
case 'varbinary':
$type[] = 'blob';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: '.$db_type);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
}
?>
\ No newline at end of file
<?php
/**
* The MySqlPlatform provides the behavior, features and SQL dialect of the
* MySQL database platform.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
class Doctrine_DatabasePlatform_MySqlPlatform extends Doctrine_DatabasePlatform
{
/**
* MySql reserved words.
*
* @var array
* @todo Needed? What about lazy initialization?
*/
protected static $_reservedKeywords = array(
'ADD', 'ALL', 'ALTER',
'ANALYZE', 'AND', 'AS',
'ASC', 'ASENSITIVE', 'BEFORE',
'BETWEEN', 'BIGINT', 'BINARY',
'BLOB', 'BOTH', 'BY',
'CALL', 'CASCADE', 'CASE',
'CHANGE', 'CHAR', 'CHARACTER',
'CHECK', 'COLLATE', 'COLUMN',
'CONDITION', 'CONNECTION', 'CONSTRAINT',
'CONTINUE', 'CONVERT', 'CREATE',
'CROSS', 'CURRENT_DATE', 'CURRENT_TIME',
'CURRENT_TIMESTAMP', 'CURRENT_USER', 'CURSOR',
'DATABASE', 'DATABASES', 'DAY_HOUR',
'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND',
'DEC', 'DECIMAL', 'DECLARE',
'DEFAULT', 'DELAYED', 'DELETE',
'DESC', 'DESCRIBE', 'DETERMINISTIC',
'DISTINCT', 'DISTINCTROW', 'DIV',
'DOUBLE', 'DROP', 'DUAL',
'EACH', 'ELSE', 'ELSEIF',
'ENCLOSED', 'ESCAPED', 'EXISTS',
'EXIT', 'EXPLAIN', 'FALSE',
'FETCH', 'FLOAT', 'FLOAT4',
'FLOAT8', 'FOR', 'FORCE',
'FOREIGN', 'FROM', 'FULLTEXT',
'GRANT', 'GROUP', 'HAVING',
'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE',
'HOUR_SECOND', 'IF', 'IGNORE',
'IN', 'INDEX', 'INFILE',
'INNER', 'INOUT', 'INSENSITIVE',
'INSERT', 'INT', 'INT1',
'INT2', 'INT3', 'INT4',
'INT8', 'INTEGER', 'INTERVAL',
'INTO', 'IS', 'ITERATE',
'JOIN', 'KEY', 'KEYS',
'KILL', 'LEADING', 'LEAVE',
'LEFT', 'LIKE', 'LIMIT',
'LINES', 'LOAD', 'LOCALTIME',
'LOCALTIMESTAMP', 'LOCK', 'LONG',
'LONGBLOB', 'LONGTEXT', 'LOOP',
'LOW_PRIORITY', 'MATCH', 'MEDIUMBLOB',
'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT',
'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'MOD',
'MODIFIES', 'NATURAL', 'NOT',
'NO_WRITE_TO_BINLOG', 'NULL', 'NUMERIC',
'ON', 'OPTIMIZE', 'OPTION',
'OPTIONALLY', 'OR', 'ORDER',
'OUT', 'OUTER', 'OUTFILE',
'PRECISION', 'PRIMARY', 'PROCEDURE',
'PURGE', 'RAID0', 'READ',
'READS', 'REAL', 'REFERENCES',
'REGEXP', 'RELEASE', 'RENAME',
'REPEAT', 'REPLACE', 'REQUIRE',
'RESTRICT', 'RETURN', 'REVOKE',
'RIGHT', 'RLIKE', 'SCHEMA',
'SCHEMAS', 'SECOND_MICROSECOND', 'SELECT',
'SENSITIVE', 'SEPARATOR', 'SET',
'SHOW', 'SMALLINT', 'SONAME',
'SPATIAL', 'SPECIFIC', 'SQL',
'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING',
'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_SMALL_RESULT',
'SSL', 'STARTING', 'STRAIGHT_JOIN',
'TABLE', 'TERMINATED', 'THEN',
'TINYBLOB', 'TINYINT', 'TINYTEXT',
'TO', 'TRAILING', 'TRIGGER',
'TRUE', 'UNDO', 'UNION',
'UNIQUE', 'UNLOCK', 'UNSIGNED',
'UPDATE', 'USAGE', 'USE',
'USING', 'UTC_DATE', 'UTC_TIME',
'UTC_TIMESTAMP', 'VALUES', 'VARBINARY',
'VARCHAR', 'VARCHARACTER', 'VARYING',
'WHEN', 'WHERE', 'WHILE',
'WITH', 'WRITE', 'X509',
'XOR', 'YEAR_MONTH', 'ZEROFILL'
);
/**
* Constructor.
* Creates a new MySqlPlatform.
*/
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'transactions' => true,
'savepoints' => false,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => true,
'LOBs' => true,
'replace' => true,
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => 'emulated',
'identifier_quoting' => true,
'pattern_escaping' => true
);
$this->_properties['string_quoting'] = array(
'start' => "'",
'end' => "'",
'escape' => '\\',
'escape_pattern' => '\\');
$this->_properties['identifier_quoting'] = array(
'start' => '`',
'end' => '`',
'escape' => '`');
$this->_properties['sql_comments'] = array(
array('start' => '-- ', 'end' => "\n", 'escape' => false),
array('start' => '#', 'end' => "\n", 'escape' => false),
array('start' => '/*', 'end' => '*/', 'escape' => false),
);
$this->properties['varchar_max_length'] = 255;
}
/**
* returns the regular expression operator
*
* @return string
* @override
*/
public function getRegexpExpression()
{
return 'RLIKE';
}
/**
* return string to call a function to get random value inside an SQL statement
*
* @return string to generate float between 0 and 1
*/
public function getRandomExpression()
{
return 'RAND()';
}
/**
* Builds a pattern matching string.
*
* EXPERIMENTAL
*
* WARNING: this function is experimental and may change signature at
* any time until labelled as non-experimental.
*
* @param array $pattern even keys are strings, odd are patterns (% and _)
* @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
* @param string $field optional field name that is being matched against
* (might be required when emulating ILIKE)
*
* @return string SQL pattern
* @override
*/
public function getMatchPatternExpression($pattern, $operator = null, $field = null)
{
$match = '';
if ( ! is_null($operator)) {
$field = is_null($field) ? '' : $field.' ';
$operator = strtoupper($operator);
switch ($operator) {
// case insensitive
case 'ILIKE':
$match = $field.'LIKE ';
break;
// case sensitive
case 'LIKE':
$match = $field.'LIKE BINARY ';
break;
default:
throw new Doctrine_Expression_Mysql_Exception('not a supported operator type:'. $operator);
}
}
$match.= "'";
foreach ($pattern as $key => $value) {
if ($key % 2) {
$match .= $value;
} else {
$match .= $this->conn->escapePattern($this->conn->escape($value));
}
}
$match.= "'";
$match.= $this->patternEscapeString();
return $match;
}
/**
* Returns global unique identifier
*
* @return string to get global unique identifier
* @override
*/
public function getGuidExpression()
{
return 'UUID()';
}
/**
* Returns a series of strings concatinated
*
* concat() accepts an arbitrary number of parameters. Each parameter
* must contain an expression or an array with expressions.
*
* @param string|array(string) strings that will be concatinated.
* @override
*/
public function getConcatExpression()
{
$args = func_get_args();
return 'CONCAT(' . join(', ', (array) $args) . ')';
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
*
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
* @override
*/
public function getNativeDeclaration($field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'char':
$length = ( ! empty($field['length'])) ? $field['length'] : false;
return $length ? 'CHAR('.$length.')' : 'CHAR(255)';
case 'varchar':
case 'array':
case 'object':
case 'string':
case 'gzip':
if ( ! isset($field['length'])) {
if (array_key_exists('default', $field)) {
$field['length'] = $this->conn->varchar_max_length;
} else {
$field['length'] = false;
}
}
$length = ($field['length'] <= $this->conn->varchar_max_length) ? $field['length'] : false;
$fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
: ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
case 'clob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYTEXT';
} elseif ($length <= 65532) {
return 'TEXT';
} elseif ($length <= 16777215) {
return 'MEDIUMTEXT';
}
}
return 'LONGTEXT';
case 'blob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYBLOB';
} elseif ($length <= 65532) {
return 'BLOB';
} elseif ($length <= 16777215) {
return 'MEDIUMBLOB';
}
}
return 'LONGBLOB';
case 'enum':
if ($this->conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
$values = array();
foreach ($field['values'] as $value) {
$values[] = $this->conn->quote($value, 'varchar');
}
return 'ENUM('.implode(', ', $values).')';
}
// fall back to integer
case 'integer':
case 'int':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 1) {
return 'TINYINT';
} elseif ($length == 2) {
return 'SMALLINT';
} elseif ($length == 3) {
return 'MEDIUMINT';
} elseif ($length == 4) {
return 'INT';
} elseif ($length > 4) {
return 'BIGINT';
}
}
return 'INT';
case 'boolean':
return 'TINYINT(1)';
case 'date':
return 'DATE';
case 'time':
return 'TIME';
case 'timestamp':
return 'DATETIME';
case 'float':
case 'double':
return 'DOUBLE';
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'DECIMAL('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a Doctrine datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
* @override
*/
public function getPortableDeclaration(array $field)
{
$dbType = strtolower($field['type']);
$dbType = strtok($dbType, '(), ');
if ($dbType == 'national') {
$dbType = strtok('(), ');
}
if (isset($field['length'])) {
$length = $field['length'];
$decimal = '';
} else {
$length = strtok('(), ');
$decimal = strtok('(), ');
}
$type = array();
$unsigned = $fixed = null;
if ( ! isset($field['name'])) {
$field['name'] = '';
}
$values = null;
switch ($dbType) {
case 'tinyint':
$type[] = 'integer';
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 1;
break;
case 'smallint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 2;
break;
case 'mediumint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 3;
break;
case 'int':
case 'integer':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 4;
break;
case 'bigint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 8;
break;
case 'tinytext':
case 'mediumtext':
case 'longtext':
case 'text':
case 'text':
case 'varchar':
$fixed = false;
case 'string':
case 'char':
$type[] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($dbType, 'text')) {
$type[] = 'clob';
if ($decimal == 'binary') {
$type[] = 'blob';
}
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'enum':
$type[] = 'enum';
preg_match_all('/\'((?:\'\'|[^\'])*)\'/', $field['type'], $matches);
$length = 0;
$fixed = false;
if (is_array($matches)) {
foreach ($matches[1] as &$value) {
$value = str_replace('\'\'', '\'', $value);
$length = max($length, strlen($value));
}
if ($length == '1' && count($matches[1]) == 2) {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
} else {
$values = $matches[1];
}
}
$type[] = 'integer';
break;
case 'set':
$fixed = false;
$type[] = 'text';
$type[] = 'integer';
break;
case 'date':
$type[] = 'date';
$length = null;
break;
case 'datetime':
case 'timestamp':
$type[] = 'timestamp';
$length = null;
break;
case 'time':
$type[] = 'time';
$length = null;
break;
case 'float':
case 'double':
case 'real':
$type[] = 'float';
$unsigned = preg_match('/ unsigned/i', $field['type']);
break;
case 'unknown':
case 'decimal':
case 'numeric':
$type[] = 'decimal';
$unsigned = preg_match('/ unsigned/i', $field['type']);
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
$type[] = 'blob';
$length = null;
break;
case 'year':
$type[] = 'integer';
$type[] = 'date';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: ' . $dbType);
}
$length = ((int) $length == 0) ? null : (int) $length;
if ($values === null) {
return array('type' => $type, 'length' => $length, 'unsigned' => $unsigned, 'fixed' => $fixed);
} else {
return array('type' => $type, 'length' => $length, 'unsigned' => $unsigned, 'fixed' => $fixed, 'values' => $values);
}
}
/**
* Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
* of a field declaration to be used in statements like CREATE TABLE.
*
* @param string $charset name of the charset
* @return string DBMS specific SQL code portion needed to set the CHARACTER SET
* of a field declaration.
*/
public function getCharsetFieldDeclaration($charset)
{
return 'CHARACTER SET ' . $charset;
}
/**
* Obtain DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration to be used in statements like CREATE TABLE.
*
* @param string $collation name of the collation
* @return string DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration.
*/
public function getCollationFieldDeclaration($collation)
{
return 'COLLATE ' . $collation;
}
/**
* Whether the platform prefers identity columns for ID generation.
* MySql prefers "autoincrement" identity columns since sequences can only
* be emulated with a table.
*
* @return boolean
* @override
*/
public function prefersIdentityColumns()
{
return true;
}
}
?>
\ No newline at end of file
<?php
class Doctrine_DatabasePlatform_OraclePlatform extends Doctrine_DatabasePlatform
{
/**
* Constructor.
*/
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => true,
'indexes' => true,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => true,
'affected_rows' => true,
'transactions' => true,
'savepoints' => true,
'limit_queries' => true,
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => false, // implementation is broken
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => true,
'identifier_quoting' => true,
'pattern_escaping' => true,
);
}
/**
* Adds an driver-specific LIMIT clause to the query
*
* @param string $query query to modify
* @param integer $limit limit the number of rows
* @param integer $offset start reading from given offset
* @return string the modified query
* @override
*/
public function writeLimitClause($query, $limit = false, $offset = false)
{
return $this->_createLimitSubquery($query, $limit, $offset);
}
private function _createLimitSubquery($query, $limit, $offset, $column = null)
{
$limit = (int) $limit;
$offset = (int) $offset;
if (preg_match('/^\s*SELECT/i', $query)) {
if ( ! preg_match('/\sFROM\s/i', $query)) {
$query .= " FROM dual";
}
if ($limit > 0) {
$max = $offset + $limit;
$column = $column === null ? '*' : $column;
if ($offset > 0) {
$min = $offset + 1;
$query = 'SELECT b.'.$column.' FROM ('.
'SELECT a.*, ROWNUM AS doctrine_rownum FROM ('
. $query . ') a '.
') b '.
'WHERE doctrine_rownum BETWEEN ' . $min . ' AND ' . $max;
} else {
$query = 'SELECT a.'.$column.' FROM (' . $query .') a WHERE ROWNUM <= ' . $max;
}
}
}
return $query;
}
/**
* Creates the SQL for Oracle that can be used in the subquery for the limit-subquery
* algorithm.
*
* @override
*/
public function writeLimitClauseInSubquery(Doctrine_ClassMetadata $rootClass,
$query, $limit = false, $offset = false)
{
// NOTE: no composite key support
$columnNames = $rootClass->getIdentifierColumnNames();
if (count($columnNames) > 1) {
throw new Doctrine_Connection_Exception("Composite keys in LIMIT queries are "
. "currently not supported.");
}
$column = $columnNames[0];
return $this->_createLimitSubquery($query, $limit, $offset, $column);
}
/**
* return string to call a function to get a substring inside an SQL statement
*
* Note: Not SQL92, but common functionality.
*
* @param string $value an sql string literal or column name/alias
* @param integer $position where to start the substring portion
* @param integer $length the substring portion length
* @return string SQL substring function with given parameters
* @override
*/
public function getSubstringExpression($value, $position, $length = null)
{
if ($length !== null)
return "SUBSTR($value, $position, $length)";
return "SUBSTR($value, $position)";
}
/**
* Return string to call a variable with the current timestamp inside an SQL statement
* There are three special variables for current date and time:
* - CURRENT_TIMESTAMP (date and time, TIMESTAMP type)
* - CURRENT_DATE (date, DATE type)
* - CURRENT_TIME (time, TIME type)
*
* @return string to call a variable with the current timestamp
* @override
*/
public function getNowExpression($type = 'timestamp')
{
switch ($type) {
case 'date':
case 'time':
case 'timestamp':
default:
return 'TO_CHAR(CURRENT_TIMESTAMP, \'YYYY-MM-DD HH24:MI:SS\')';
}
}
/**
* random
*
* @return string an oracle SQL string that generates a float between 0 and 1
* @override
*/
public function getRandomExpression()
{
return 'dbms_random.value';
}
/**
* Returns global unique identifier
*
* @return string to get global unique identifier
* @override
*/
public function getGuidExpression()
{
return 'SYS_GUID()';
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
* @override
*/
public function getNativeDeclaration(array $field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'string':
case 'array':
case 'object':
case 'gzip':
case 'char':
case 'varchar':
$length = !empty($field['length'])
? $field['length'] : 16777215; // TODO: $this->conn->options['default_text_field_length'];
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? 'CHAR('.$length.')' : 'VARCHAR2('.$length.')';
case 'clob':
return 'CLOB';
case 'blob':
return 'BLOB';
case 'integer':
case 'enum':
case 'int':
if ( ! empty($field['length'])) {
return 'NUMBER('.$field['length'].')';
}
return 'INT';
case 'boolean':
return 'NUMBER(1)';
case 'date':
case 'time':
case 'timestamp':
return 'DATE';
case 'float':
case 'double':
return 'NUMBER';
case 'decimal':
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'NUMBER(*,'.$scale.')';
default:
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a doctrine datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
* @throws Doctrine_DataDict_Oracle_Exception
* @override
*/
public function getPortableDeclaration(array $field)
{
if ( ! isset($field['data_type'])) {
throw new Doctrine_DataDict_Exception('Native oracle definition must have a data_type key specified');
}
$dbType = strtolower($field['data_type']);
$type = array();
$length = $unsigned = $fixed = null;
if ( ! empty($field['data_length'])) {
$length = $field['data_length'];
}
if ( ! isset($field['column_name'])) {
$field['column_name'] = '';
}
switch ($dbType) {
case 'integer':
case 'pls_integer':
case 'binary_integer':
$type[] = 'integer';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['column_name'])) {
$type = array_reverse($type);
}
}
break;
case 'varchar':
case 'varchar2':
case 'nvarchar2':
$fixed = false;
case 'char':
case 'nchar':
$type[] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['column_name'])) {
$type = array_reverse($type);
}
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'date':
case 'timestamp':
$type[] = 'timestamp';
$length = null;
break;
case 'float':
$type[] = 'float';
break;
case 'number':
if ( ! empty($field['data_scale'])) {
$type[] = 'decimal';
} else {
$type[] = 'integer';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['column_name'])) {
$type = array_reverse($type);
}
}
}
break;
case 'long':
$type[] = 'string';
case 'clob':
case 'nclob':
$type[] = 'clob';
break;
case 'blob':
case 'raw':
case 'long raw':
case 'bfile':
$type[] = 'blob';
$length = null;
break;
case 'rowid':
case 'urowid':
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: ' . $dbType);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
}
?>
\ No newline at end of file
<?php
class Doctrine_DatabasePlatform_PostgreSqlPlatform extends Doctrine_DatabasePlatform
{
/**
* The reserved keywords by pgsql. Ordered alphabetically.
*
* @param array
* @todo Nedded? What about lazy initialization?
*/
protected static $_reservedKeywords = array(
'abort', 'absolute', 'access', 'action', 'add', 'after', 'aggregate',
'all', 'alter', 'analyse', 'analyze', 'and', 'any', 'as', 'asc',
'assertion', 'assignment', 'at', 'authorization', 'backward', 'before',
'begin', 'between', 'bigint', 'binary', 'bit', 'boolean', 'both',
'by', 'cache', 'called', 'cascade', 'case', 'cast', 'chain', 'char',
'character', 'characteristics', 'check', 'checkpoint', 'class',
'close', 'cluster', 'coalesce', 'collate', 'column', 'comment',
'commit', 'committed', 'constraint', 'constraints', 'conversion',
'convert', 'copy', 'create', 'createdb', 'createuser', 'cross',
'current_date', 'current_time', 'current_timestamp', 'current_user',
'cursor', 'cycle', 'database', 'day', 'deallocate', 'dec', 'decimal',
'declare', 'default', 'deferrable', 'deferred', 'definer', 'delete',
'delimiter', 'delimiters', 'desc', 'distinct', 'do', 'domain', 'double',
'drop', 'each', 'else', 'encoding', 'encrypted', 'end', 'escape',
'except', 'exclusive', 'execute', 'exists', 'explain', 'external',
'extract', 'false', 'fetch', 'float', 'for', 'force', 'foreign',
'forward', 'freeze', 'from', 'full', 'function', 'get', 'global',
'grant', 'group', 'handler', 'having', 'hour', 'ilike', 'immediate',
'immutable', 'implicit', 'in', 'increment', 'index', 'inherits',
'initially', 'inner', 'inout', 'input', 'insensitive', 'insert',
'instead', 'int', 'integer', 'intersect', 'interval', 'into', 'invoker',
'is', 'isnull', 'isolation', 'join', 'key', 'lancompiler', 'language',
'leading', 'left', 'level', 'like', 'limit', 'listen', 'load', 'local',
'localtime', 'localtimestamp', 'location', 'lock', 'match', 'maxvalue',
'minute', 'minvalue', 'mode', 'month', 'move', 'names', 'national',
'natural', 'nchar', 'new', 'next', 'no', 'nocreatedb', 'nocreateuser',
'none', 'not', 'nothing', 'notify', 'notnull', 'null', 'nullif',
'numeric', 'of', 'off', 'offset', 'oids', 'old', 'on', 'only', 'operator',
'option', 'or', 'order', 'out', 'outer', 'overlaps', 'overlay',
'owner', 'partial', 'password', 'path', 'pendant', 'placing', 'position',
'precision', 'prepare', 'primary', 'prior', 'privileges', 'procedural',
'procedure', 'read', 'real', 'recheck', 'references', 'reindex',
'relative', 'rename', 'replace', 'reset', 'restrict', 'returns',
'revoke', 'right', 'rollback', 'row', 'rule', 'schema', 'scroll',
'second', 'security', 'select', 'sequence', 'serializable', 'session',
'session_user', 'set', 'setof', 'share', 'show', 'similar', 'simple',
'smallint', 'some', 'stable', 'start', 'statement', 'statistics',
'stdin', 'stdout', 'storage', 'strict', 'substring', 'sysid', 'table',
'temp', 'template', 'temporary', 'then', 'time', 'timestamp', 'to',
'toast', 'trailing', 'transaction', 'treat', 'trigger', 'trim', 'true',
'truncate', 'trusted', 'type', 'unencrypted', 'union', 'unique',
'unknown', 'unlisten', 'until', 'update', 'usage', 'user', 'using',
'vacuum', 'valid', 'validator', 'values', 'varchar', 'varying',
'verbose', 'version', 'view', 'volatile', 'when', 'where', 'with',
'without', 'work', 'write', 'year','zone');
/**
* Constructor.
* Creates a new PostgreSqlPlatform.
*/
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => true,
'indexes' => true,
'affected_rows' => true,
'summary_functions' => true,
'order_by_text' => true,
'transactions' => true,
'savepoints' => true,
'current_id' => true,
'limit_queries' => true,
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => 'emulated',
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => true,
'identifier_quoting' => true,
'pattern_escaping' => true,
);
$this->_properties['string_quoting'] = array('start' => "'",
'end' => "'",
'escape' => "'",
'escape_pattern' => '\\');
$this->_properties['identifier_quoting'] = array('start' => '"',
'end' => '"',
'escape' => '"');
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
*
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
* @override
*/
public function getNativeDeclaration(array $field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'char':
case 'string':
case 'array':
case 'object':
case 'varchar':
case 'gzip':
// TODO: what is the maximum VARCHAR length in pgsql ?
$length = (isset($field['length']) && $field['length'] && $field['length'] < 10000) ? $field['length'] : null;
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR('.$this->conn->options['default_text_field_length'].')')
: ($length ? 'VARCHAR(' .$length . ')' : 'TEXT');
case 'clob':
return 'TEXT';
case 'blob':
return 'BYTEA';
case 'enum':
case 'integer':
case 'int':
if ( ! empty($field['autoincrement'])) {
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length > 4) {
return 'BIGSERIAL';
}
}
return 'SERIAL';
}
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 2) {
return 'SMALLINT';
} elseif ($length == 3 || $length == 4) {
return 'INT';
} elseif ($length > 4) {
return 'BIGINT';
}
}
return 'INT';
case 'boolean':
return 'BOOLEAN';
case 'date':
return 'DATE';
case 'time':
return 'TIME without time zone';
case 'timestamp':
return 'TIMESTAMP without time zone';
case 'float':
case 'double':
return 'FLOAT';
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'NUMERIC('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to a portable Doctrine datatype and length
*
* @param array $field native field description
*
* @return array containing the various possible types, length, sign, fixed
* @override
*/
public function getPortableDeclaration(array $field)
{
$length = (isset($field['length'])) ? $field['length'] : null;
if ($length == '-1' && isset($field['atttypmod'])) {
$length = $field['atttypmod'] - 4;
}
if ((int)$length <= 0) {
$length = null;
}
$type = array();
$unsigned = $fixed = null;
if ( ! isset($field['name'])) {
$field['name'] = '';
}
$dbType = strtolower($field['type']);
switch ($dbType) {
case 'smallint':
case 'int2':
$type[] = 'integer';
$unsigned = false;
$length = 2;
if ($length == '2') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
}
break;
case 'int':
case 'int4':
case 'integer':
case 'serial':
case 'serial4':
$type[] = 'integer';
$unsigned = false;
$length = 4;
break;
case 'bigint':
case 'int8':
case 'bigserial':
case 'serial8':
$type[] = 'integer';
$unsigned = false;
$length = 8;
break;
case 'bool':
case 'boolean':
$type[] = 'boolean';
$length = 1;
break;
case 'text':
case 'varchar':
case 'interval':
case '_varchar':
$fixed = false;
case 'unknown':
case 'char':
case 'bpchar':
$type[] = 'string';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($dbType, 'text')) {
$type[] = 'clob';
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'date':
$type[] = 'date';
$length = null;
break;
case 'datetime':
case 'timestamp':
case 'timestamptz':
$type[] = 'timestamp';
$length = null;
break;
case 'time':
$type[] = 'time';
$length = null;
break;
case 'float':
case 'float4':
case 'float8':
case 'double':
case 'double precision':
case 'real':
$type[] = 'float';
break;
case 'decimal':
case 'money':
case 'numeric':
$type[] = 'decimal';
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
case 'bytea':
$type[] = 'blob';
$length = null;
break;
case 'oid':
$type[] = 'blob';
$type[] = 'clob';
$length = null;
break;
case 'year':
$type[] = 'integer';
$type[] = 'date';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: '.$dbType);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
/**
* Returns the md5 sum of a field.
*
* Note: Not SQL92, but common functionality
*
* md5() works with the default PostgreSQL 8 versions.
*
* If you are using PostgreSQL 7.x or older you need
* to make sure that the digest procedure is installed.
* If you use RPMS (Redhat and Mandrake) install the postgresql-contrib
* package. You must then install the procedure by running this shell command:
* <code>
* psql [dbname] < /usr/share/pgsql/contrib/pgcrypto.sql
* </code>
* You should make sure you run this as the postgres user.
*
* @return string
* @override
*/
public function getMd5Expression($column)
{
$column = $this->getIdentifier($column);
if ($this->_version > 7) {
return 'MD5(' . $column . ')';
} else {
return 'encode(digest(' . $column .', md5), hex)';
}
}
/**
* Returns part of a string.
*
* Note: Not SQL92, but common functionality.
*
* @param string $value the target $value the string or the string column.
* @param int $from extract from this characeter.
* @param int $len extract this amount of characters.
* @return string sql that extracts part of a string.
* @override
*/
public function getSubstringExpression($value, $from, $len = null)
{
$value = $this->getIdentifier($value);
if ($len === null) {
$len = $this->getIdentifier($len);
return 'SUBSTR(' . $value . ', ' . $from . ')';
} else {
return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
}
}
/**
* PostgreSQLs AGE(<timestamp1> [, <timestamp2>]) function.
*
* @param string $timestamp1 timestamp to subtract from NOW()
* @param string $timestamp2 optional; if given: subtract arguments
* @return string
*/
public function getAgeExpression($timestamp1, $timestamp2 = null)
{
if ( $timestamp2 == null ) {
return 'AGE(' . $timestamp1 . ')';
}
return 'AGE(' . $timestamp1 . ', ' . $timestamp2 . ')';
}
/**
* PostgreSQLs DATE_PART( <text>, <time> ) function.
*
* @param string $text what to extract
* @param string $time timestamp or interval to extract from
* @return string
*/
public function getDatePartExpression($text, $time)
{
return 'DATE_PART(' . $text . ', ' . $time . ')';
}
/**
* PostgreSQLs TO_CHAR( <time>, <text> ) function.
*
* @param string $time timestamp or interval
* @param string $text how to the format the output
* @return string
*/
public function getToCharExpression($time, $text)
{
return 'TO_CHAR(' . $time . ', ' . $text . ')';
}
/**
* Returns the SQL string to return the current system date and time.
*
* @return string
*/
public function getNowExpression()
{
return 'LOCALTIMESTAMP(0)';
}
/**
* regexp
*
* @return string the regular expression operator
* @override
*/
public function getRegexpExpression()
{
return 'SIMILAR TO';
}
/**
* return string to call a function to get random value inside an SQL statement
*
* @return return string to generate float between 0 and 1
* @access public
* @override
*/
public function getRandomExpression()
{
return 'RANDOM()';
}
/**
* build a pattern matching string
*
* EXPERIMENTAL
*
* WARNING: this function is experimental and may change signature at
* any time until labelled as non-experimental
*
* @access public
*
* @param array $pattern even keys are strings, odd are patterns (% and _)
* @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
* @param string $field optional field name that is being matched against
* (might be required when emulating ILIKE)
*
* @return string SQL pattern
* @override
*/
public function getMatchPatternExpression($pattern, $operator = null, $field = null)
{
$match = '';
if ( ! is_null($operator)) {
$field = is_null($field) ? '' : $field.' ';
$operator = strtoupper($operator);
switch ($operator) {
// case insensitive
case 'ILIKE':
$match = $field.'ILIKE ';
break;
// case sensitive
case 'LIKE':
$match = $field.'LIKE ';
break;
default:
throw new Doctrine_Expression_Pgsql_Exception('not a supported operator type:'. $operator);
}
}
$match.= "'";
foreach ($pattern as $key => $value) {
if ($key % 2) {
$match.= $value;
} else {
$match.= $this->conn->escapePattern($this->conn->escape($value));
}
}
$match.= "'";
$match.= $this->patternEscapeString();
return $match;
}
/**
* parses a literal boolean value and returns
* proper sql equivalent
*
* @param string $value boolean value to be parsed
* @return string parsed boolean value
*/
public function parseBoolean($value)
{
return $value;
}
}
?>
\ No newline at end of file
<?php
#namespace Doctrine::DBAL::Platforms;
/**
* Enter description here...
*
* @since 2.0
*/
class Doctrine_DatabasePlatform_SqlitePlatform extends Doctrine_DatabasePlatform
{
/**
* the constructor
*/
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => true,
'LOBs' => true,
'replace' => true,
'transactions' => true,
'savepoints' => false,
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => false, // not implemented
'prepared_statements' => 'emulated',
'identifier_quoting' => true,
'pattern_escaping' => false,
);
}
/**
* Returns the md5 sum of the data that SQLite's md5() function receives.
*
* @param mixed $data
* @return string
*/
public static function md5Impl($data)
{
return md5($data);
}
/**
* Returns the modules of the data that SQLite's mod() function receives.
*
* @param integer $dividend
* @param integer $divisor
* @return string
*/
public static function modImpl($dividend, $divisor)
{
return $dividend % $divisor;
}
/**
* locate
* returns the position of the first occurrence of substring $substr in string $str that
* SQLite's locate() function receives
*
* @param string $substr literal string to find
* @param string $str literal string
* @return string
*/
public static function locateImpl($substr, $str)
{
return strpos($str, $substr);
}
public static function sha1Impl($str)
{
return sha1($str);
}
public static function ltrimImpl($str)
{
return ltrim($str);
}
public static function rtrimImpl($str)
{
return rtrim($str);
}
public static function trimImpl($str)
{
return trim($str);
}
/**
* returns the regular expression operator
*
* @return string
* @override
*/
public function getRegexpExpression()
{
return 'RLIKE';
}
/**
* Returns a string to call a function to compute the
* soundex encoding of a string
*
* The string "?000" is returned if the argument is NULL.
*
* @param string $value
* @return string SQL soundex function with given parameter
*/
public function getSoundexExpression($value)
{
return 'SOUNDEX(' . $value . ')';
}
/**
* Return string to call a variable with the current timestamp inside an SQL statement
* There are three special variables for current date and time.
*
* @return string sqlite function as string
* @override
*/
public function getNowExpression($type = 'timestamp')
{
switch ($type) {
case 'time':
return 'time(\'now\')';
case 'date':
return 'date(\'now\')';
case 'timestamp':
default:
return 'datetime(\'now\')';
}
}
/**
* return string to call a function to get random value inside an SQL statement
*
* @return string to generate float between 0 and 1
* @override
*/
public function getRandomExpression()
{
return '((RANDOM() + 2147483648) / 4294967296)';
}
/**
* return string to call a function to get a substring inside an SQL statement
*
* Note: Not SQL92, but common functionality.
*
* SQLite only supports the 2 parameter variant of this function
*
* @param string $value an sql string literal or column name/alias
* @param integer $position where to start the substring portion
* @param integer $length the substring portion length
* @return string SQL substring function with given parameters
* @override
*/
public function getSubstringExpression($value, $position, $length = null)
{
if ($length !== null) {
return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')';
}
return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))';
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
*
* @param array $field associative array with the name of the properties
* of the field being declared as array indexes. Currently, the types
* of supported field properties are as follows:
*
* length
* Integer value that determines the maximum length of the text
* field. If this argument is missing the field should be
* declared to have the longest length allowed by the DBMS.
*
* default
* Text value to be used as default for this field.
*
* notnull
* Boolean flag that indicates whether this field is constrained
* to not be set to null.
* @author Lukas Smith (PEAR MDB2 library)
* @return string DBMS specific SQL code portion that should be used to
* declare the specified field.
* @override
*/
public function getNativeDeclaration(array $field)
{
if ( ! isset($field['type'])) {
throw new Doctrine_DataDict_Exception('Missing column type.');
}
switch ($field['type']) {
case 'text':
case 'object':
case 'array':
case 'string':
case 'char':
case 'gzip':
case 'varchar':
$length = (isset($field['length']) && $field['length']) ? $field['length'] : null;
$fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->getAttribute(Doctrine::ATTR_DEFAULT_TEXTFLD_LENGTH).')')
: ($length ? 'VARCHAR('.$length.')' : 'TEXT');
case 'clob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYTEXT';
} elseif ($length <= 65535) {
return 'TEXT';
} elseif ($length <= 16777215) {
return 'MEDIUMTEXT';
}
}
return 'LONGTEXT';
case 'blob':
if ( ! empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYBLOB';
} elseif ($length <= 65535) {
return 'BLOB';
} elseif ($length <= 16777215) {
return 'MEDIUMBLOB';
}
}
return 'LONGBLOB';
case 'enum':
case 'integer':
case 'boolean':
case 'int':
return 'INTEGER';
case 'date':
return 'DATE';
case 'time':
return 'TIME';
case 'timestamp':
return 'DATETIME';
case 'float':
case 'double':
return 'DOUBLE';//($this->conn->options['fixed_float'] ? '('.
//($this->conn->options['fixed_float']+2).','.$this->conn->options['fixed_float'].')' : '');
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
$scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
return 'DECIMAL('.$length.','.$scale.')';
}
throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
}
/**
* Maps a native array description of a field to Doctrine datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
* @override
*/
public function getPortableDeclaration(array $field)
{
$dbType = strtolower($field['type']);
$length = (isset($field['length'])) ? $field['length'] : null;
$unsigned = (isset($field['unsigned'])) ? $field['unsigned'] : null;
$fixed = null;
$type = array();
if ( ! isset($field['name'])) {
$field['name'] = '';
}
switch ($dbType) {
case 'boolean':
$type[] = 'boolean';
break;
case 'tinyint':
$type[] = 'integer';
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 1;
break;
case 'smallint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 2;
break;
case 'mediumint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 3;
break;
case 'int':
case 'integer':
case 'serial':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 4;
break;
case 'bigint':
case 'bigserial':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 8;
break;
case 'clob':
case 'tinytext':
case 'mediumtext':
case 'longtext':
case 'text':
case 'varchar':
case 'varchar2':
$fixed = false;
case 'char':
$type[] = 'text';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($dbType, 'text')) {
$type[] = 'clob';
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'date':
$type[] = 'date';
$length = null;
break;
case 'datetime':
case 'timestamp':
$type[] = 'timestamp';
$length = null;
break;
case 'time':
$type[] = 'time';
$length = null;
break;
case 'float':
case 'double':
case 'real':
$type[] = 'float';
$length = null;
break;
case 'decimal':
case 'numeric':
$type[] = 'decimal';
$length = null;
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
$type[] = 'blob';
$length = null;
break;
case 'year':
$type[] = 'integer';
$type[] = 'date';
$length = null;
break;
default:
throw new Doctrine_DataDict_Exception('unknown database attribute type: '.$dbType);
}
return array('type' => $type,
'length' => $length,
'unsigned' => $unsigned,
'fixed' => $fixed);
}
}
?>
\ No newline at end of file
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
* NOTE: Methods that are intended for internal use only but must be public * NOTE: Methods that are intended for internal use only but must be public
* are marked INTERNAL: and begin with an underscore "_" to indicate that they * are marked INTERNAL: and begin with an underscore "_" to indicate that they
* ideally would not be public and to minimize naming collisions. * ideally would not be public and to minimize naming collisions.
*
* The "final" modifiers on most methods prevent accidental overrides.
* It is not desirable that subclasses can override these methods.
* The persistence layer should stay in the background as much as possible.
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
...@@ -81,7 +85,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable ...@@ -81,7 +85,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
/** /**
* Index used for creating object identifiers (oid's). * Index used for creating object identifiers (oid's).
* *
* @var integer $index * @var integer
*/ */
private static $_index = 1; private static $_index = 1;
...@@ -240,14 +244,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable ...@@ -240,14 +244,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
} }
} }
} }
/**
* INTERNAL:
*/
/*final public function _setIdentifier(array $identifier)
{
$this->_id = $identifier;
}*/
/** /**
* Serializes the entity. * Serializes the entity.
......
...@@ -168,14 +168,26 @@ class Doctrine_EntityManager ...@@ -168,14 +168,26 @@ class Doctrine_EntityManager
} }
/** /**
* Gets the transaction object used by the EntityManager to manage * Starts a database transaction.
* database transactions. */
* public function beginTransaction()
* @return Doctrine::DBAL::Transaction {
return $this->_conn->beginTransaction();
}
/**
* Commits a running database transaction.
* This causes a flush() of the EntityManager if the flush mode is set to
* AUTO or COMMIT.
*
* @return unknown
*/ */
public function getTransaction() public function commit()
{ {
return $this->_conn->getTransaction(); if ($this->_flushMode == self::FLUSHMODE_AUTO || $this->_flushMode == self::FLUSHMODE_COMMIT) {
$this->flush();
}
return $this->_conn->commitTransaction();
} }
/** /**
......
...@@ -18,11 +18,16 @@ ...@@ -18,11 +18,16 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
#namespace Doctrine::Common::Events;
/** /**
* EventSubscriber. * An EventSubscriber knows itself what events it is interested in.
* If an EventSubscriber is added to an EventManager, the manager invokes
* getSubscribedEvents() and registers the subscriber as a listener for all
* returned events.
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 2.0 * @since 2.0
......
...@@ -1069,6 +1069,7 @@ class Doctrine_Export extends Doctrine_Connection_Module ...@@ -1069,6 +1069,7 @@ class Doctrine_Export extends Doctrine_Connection_Module
* occurred during the create table operation * occurred during the create table operation
* @param array $classes * @param array $classes
* @return void * @return void
* @todo ORM stuff
*/ */
public function exportClasses(array $classes) public function exportClasses(array $classes)
{ {
...@@ -1279,6 +1280,7 @@ class Doctrine_Export extends Doctrine_Connection_Module ...@@ -1279,6 +1280,7 @@ class Doctrine_Export extends Doctrine_Connection_Module
* occurred during the create table operation * occurred during the create table operation
* @return boolean whether or not the export operation was successful * @return boolean whether or not the export operation was successful
* false if table already existed in the database * false if table already existed in the database
* @todo ORM stuff
*/ */
public function exportTable(Doctrine_ClassMetadata $metadata) public function exportTable(Doctrine_ClassMetadata $metadata)
{ {
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Expression_Driver');
/** /**
* Doctrine_Expression_Firebird * Doctrine_Expression_Firebird
* *
...@@ -30,28 +30,10 @@ Doctrine::autoload('Doctrine_Expression_Driver'); ...@@ -30,28 +30,10 @@ Doctrine::autoload('Doctrine_Expression_Driver');
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lorenzo Alberton <l.alberton@quipo.it> (PEAR MDB2 Interbase driver) * @author Lorenzo Alberton <l.alberton@quipo.it> (PEAR MDB2 Interbase driver)
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @todo Remove
*/ */
class Doctrine_Expression_Firebird extends Doctrine_Expression_Driver class Doctrine_Expression_Firebird extends Doctrine_Expression_Driver
{ {
/**
* return string for internal table used when calling only a function
*
* @return string for internal table used when calling only a function
* @access public
*/
public function functionTable()
{
return ' FROM RDB$DATABASE';
}
/**
* build string to define escape pattern string
*
* @return string define escape pattern
*/
function patternEscapeString()
{
return " ESCAPE '". $this->conn->string_quoting['escape_pattern'] ."'";
}
} }
\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Expression');
/** /**
* Doctrine_Expression_Informix * Doctrine_Expression_Informix
* *
...@@ -28,7 +28,8 @@ Doctrine::autoload('Doctrine_Expression'); ...@@ -28,7 +28,8 @@ Doctrine::autoload('Doctrine_Expression');
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Remove
*/ */
class Doctrine_Expression_Informix extends Doctrine_Expression class Doctrine_Expression_Informix extends Doctrine_Expression
{ } { }
\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Expression_Driver');
/** /**
* Doctrine_Expression_Mssql * Doctrine_Expression_Mssql
* *
...@@ -28,65 +28,10 @@ Doctrine::autoload('Doctrine_Expression_Driver'); ...@@ -28,65 +28,10 @@ Doctrine::autoload('Doctrine_Expression_Driver');
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Remove
*/ */
class Doctrine_Expression_Mssql extends Doctrine_Expression_Driver class Doctrine_Expression_Mssql extends Doctrine_Expression_Driver
{ {
/**
* Return string to call a variable with the current timestamp inside an SQL statement
* There are three special variables for current date and time:
* - CURRENT_TIMESTAMP (date and time, TIMESTAMP type)
* - CURRENT_DATE (date, DATE type)
* - CURRENT_TIME (time, TIME type)
*
* @return string to call a variable with the current timestamp
* @access public
*/
public function now($type = 'timestamp')
{
switch ($type) {
case 'time':
case 'date':
case 'timestamp':
default:
return 'GETDATE()';
}
}
/**
* return string to call a function to get a substring inside an SQL statement
*
* @return string to call a function to get a substring
*/
public function substring($value, $position, $length = null)
{
if ( ! is_null($length)) {
return 'SUBSTRING(' . $value . ', ' . $position . ', ' . $length . ')';
}
return 'SUBSTRING(' . $value . ', ' . $position . ', LEN(' . $value . ') - ' . $position . ' + 1)';
}
/**
* Returns string to concatenate two or more string parameters
*
* @param string $arg1
* @param string $arg2
* @param string $values...
* @return string to concatenate two strings
*/
public function concat()
{
$args = func_get_args();
return '(' . implode(' + ', $args) . ')';
}
/**
* Returns global unique identifier
*
* @return string to get global unique identifier
*/
public function guid()
{
return 'NEWID()';
}
} }
\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Expression_Driver');
/** /**
* Doctrine_Expression_Mysql * Doctrine_Expression_Mysql
* *
...@@ -29,100 +29,9 @@ Doctrine::autoload('Doctrine_Expression_Driver'); ...@@ -29,100 +29,9 @@ Doctrine::autoload('Doctrine_Expression_Driver');
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Remove
*/ */
class Doctrine_Expression_Mysql extends Doctrine_Expression_Driver class Doctrine_Expression_Mysql extends Doctrine_Expression_Driver
{ {
/**
* returns the regular expression operator
*
* @return string
*/
public function regexp()
{
return 'RLIKE';
}
/**
* return string to call a function to get random value inside an SQL statement
*
* @return string to generate float between 0 and 1
*/
public function random()
{
return 'RAND()';
}
/**
* build a pattern matching string
*
* EXPERIMENTAL
*
* WARNING: this function is experimental and may change signature at
* any time until labelled as non-experimental
*
* @access public
*
* @param array $pattern even keys are strings, odd are patterns (% and _)
* @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
* @param string $field optional field name that is being matched against
* (might be required when emulating ILIKE)
*
* @return string SQL pattern
*/
public function matchPattern($pattern, $operator = null, $field = null)
{
$match = '';
if ( ! is_null($operator)) {
$field = is_null($field) ? '' : $field.' ';
$operator = strtoupper($operator);
switch ($operator) {
// case insensitive
case 'ILIKE':
$match = $field.'LIKE ';
break;
// case sensitive
case 'LIKE':
$match = $field.'LIKE BINARY ';
break;
default:
throw new Doctrine_Expression_Mysql_Exception('not a supported operator type:'. $operator);
}
}
$match.= "'";
foreach ($pattern as $key => $value) {
if ($key % 2) {
$match .= $value;
} else {
$match .= $this->conn->escapePattern($this->conn->escape($value));
}
}
$match.= "'";
$match.= $this->patternEscapeString();
return $match;
}
/**
* Returns global unique identifier
*
* @return string to get global unique identifier
*/
public function guid()
{
return 'UUID()';
}
/**
* Returns a series of strings concatinated
*
* concat() accepts an arbitrary number of parameters. Each parameter
* must contain an expression or an array with expressions.
*
* @param string|array(string) strings that will be concatinated.
*/
public function concat()
{
$args = func_get_args();
return 'CONCAT(' . join(', ', (array) $args) . ')';
}
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Expression_Driver');
/** /**
* Doctrine_Expression_Sqlite * Doctrine_Expression_Sqlite
* *
...@@ -28,65 +28,10 @@ Doctrine::autoload('Doctrine_Expression_Driver'); ...@@ -28,65 +28,10 @@ Doctrine::autoload('Doctrine_Expression_Driver');
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Remove
*/ */
class Doctrine_Expression_Oracle extends Doctrine_Expression_Driver class Doctrine_Expression_Oracle extends Doctrine_Expression_Driver
{ {
/**
* return string to call a function to get a substring inside an SQL statement
*
* Note: Not SQL92, but common functionality.
*
* @param string $value an sql string literal or column name/alias
* @param integer $position where to start the substring portion
* @param integer $length the substring portion length
* @return string SQL substring function with given parameters
*/
public function substring($value, $position, $length = null)
{
if ($length !== null)
return "SUBSTR($value, $position, $length)";
return "SUBSTR($value, $position)";
}
/**
* Return string to call a variable with the current timestamp inside an SQL statement
* There are three special variables for current date and time:
* - CURRENT_TIMESTAMP (date and time, TIMESTAMP type)
* - CURRENT_DATE (date, DATE type)
* - CURRENT_TIME (time, TIME type)
*
* @return string to call a variable with the current timestamp
*/
public function now($type = 'timestamp')
{
switch ($type) {
case 'date':
case 'time':
case 'timestamp':
default:
return 'TO_CHAR(CURRENT_TIMESTAMP, \'YYYY-MM-DD HH24:MI:SS\')';
}
}
/**
* random
*
* @return string an oracle SQL string that generates a float between 0 and 1
*/
public function random()
{
return 'dbms_random.value';
}
/**
* Returns global unique identifier
*
* @return string to get global unique identifier
*/
public function guid()
{
return 'SYS_GUID()';
}
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Expression_Driver');
/** /**
* Doctrine_Expression_Pgsql * Doctrine_Expression_Pgsql
* *
...@@ -29,174 +29,9 @@ Doctrine::autoload('Doctrine_Expression_Driver'); ...@@ -29,174 +29,9 @@ Doctrine::autoload('Doctrine_Expression_Driver');
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Remove
*/ */
class Doctrine_Expression_Pgsql extends Doctrine_Expression_Driver class Doctrine_Expression_Pgsql extends Doctrine_Expression_Driver
{ {
/**
* Returns the md5 sum of a field.
*
* Note: Not SQL92, but common functionality
*
* md5() works with the default PostgreSQL 8 versions.
*
* If you are using PostgreSQL 7.x or older you need
* to make sure that the digest procedure is installed.
* If you use RPMS (Redhat and Mandrake) install the postgresql-contrib
* package. You must then install the procedure by running this shell command:
* <code>
* psql [dbname] < /usr/share/pgsql/contrib/pgcrypto.sql
* </code>
* You should make sure you run this as the postgres user.
*
* @return string
*/
public function md5($column)
{
$column = $this->getIdentifier($column);
if ($this->version > 7) {
return 'MD5(' . $column . ')';
} else {
return 'encode(digest(' . $column .', md5), hex)';
}
}
/**
* Returns part of a string.
*
* Note: Not SQL92, but common functionality.
*
* @param string $value the target $value the string or the string column.
* @param int $from extract from this characeter.
* @param int $len extract this amount of characters.
* @return string sql that extracts part of a string.
*/
public function substring($value, $from, $len = null)
{
$value = $this->getIdentifier($value);
if ($len === null) {
$len = $this->getIdentifier($len);
return 'SUBSTR(' . $value . ', ' . $from . ')';
} else {
return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
}
}
/**
* PostgreSQLs AGE(<timestamp1> [, <timestamp2>]) function.
*
* @param string $timestamp1 timestamp to subtract from NOW()
* @param string $timestamp2 optional; if given: subtract arguments
* @return string
*/
public function age($timestamp1, $timestamp2 = null) {
if ( $timestamp2 == null ) {
return 'AGE(' . $timestamp1 . ')';
}
return 'AGE(' . $timestamp1 . ', ' . $timestamp2 . ')';
}
/**
* PostgreSQLs DATE_PART( <text>, <time> ) function.
*
* @param string $text what to extract
* @param string $time timestamp or interval to extract from
* @return string
*/
public function date_part($text, $time) {
return 'DATE_PART(' . $text . ', ' . $time . ')';
}
/**
* PostgreSQLs TO_CHAR( <time>, <text> ) function.
*
* @param string $time timestamp or interval
* @param string $text how to the format the output
* @return string
*/
public function to_char($time, $text) {
return 'TO_CHAR(' . $time . ', ' . $text . ')';
}
/**
* Returns the SQL string to return the current system date and time.
*
* @return string
*/
public function now()
{
return 'LOCALTIMESTAMP(0)';
}
/**
* regexp
*
* @return string the regular expression operator
*/
public function regexp()
{
return 'SIMILAR TO';
}
/**
* return string to call a function to get random value inside an SQL statement
*
* @return return string to generate float between 0 and 1
* @access public
*/
public function random()
{
return 'RANDOM()';
}
/**
* build a pattern matching string
*
* EXPERIMENTAL
*
* WARNING: this function is experimental and may change signature at
* any time until labelled as non-experimental
*
* @access public
*
* @param array $pattern even keys are strings, odd are patterns (% and _)
* @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
* @param string $field optional field name that is being matched against
* (might be required when emulating ILIKE)
*
* @return string SQL pattern
*/
public function matchPattern($pattern, $operator = null, $field = null)
{
$match = '';
if ( ! is_null($operator)) {
$field = is_null($field) ? '' : $field.' ';
$operator = strtoupper($operator);
switch ($operator) {
// case insensitive
case 'ILIKE':
$match = $field.'ILIKE ';
break;
// case sensitive
case 'LIKE':
$match = $field.'LIKE ';
break;
default:
throw new Doctrine_Expression_Pgsql_Exception('not a supported operator type:'. $operator);
}
}
$match.= "'";
foreach ($pattern as $key => $value) {
if ($key % 2) {
$match.= $value;
} else {
$match.= $this->conn->escapePattern($this->conn->escape($value));
}
}
$match.= "'";
$match.= $this->patternEscapeString();
return $match;
}
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Expression_Driver');
/** /**
* Doctrine_Expression_Sqlite * Doctrine_Expression_Sqlite
* *
...@@ -28,134 +28,10 @@ Doctrine::autoload('Doctrine_Expression_Driver'); ...@@ -28,134 +28,10 @@ Doctrine::autoload('Doctrine_Expression_Driver');
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Remove
*/ */
class Doctrine_Expression_Sqlite extends Doctrine_Expression_Driver class Doctrine_Expression_Sqlite extends Doctrine_Expression_Driver
{ {
/**
* Returns the md5 sum of the data that SQLite's md5() function receives.
*
* @param mixed $data
* @return string
*/
public static function md5Impl($data)
{
return md5($data);
}
/**
* Returns the modules of the data that SQLite's mod() function receives.
*
* @param integer $dividend
* @param integer $divisor
* @return string
*/
public static function modImpl($dividend, $divisor)
{
return $dividend % $divisor;
}
/**
* locate
* returns the position of the first occurrence of substring $substr in string $str that
* SQLite's locate() function receives
*
* @param string $substr literal string to find
* @param string $str literal string
* @return string
*/
public static function locateImpl($substr, $str)
{
return strpos($str, $substr);
}
public static function sha1Impl($str)
{
return sha1($str);
}
public static function ltrimImpl($str)
{
return ltrim($str);
}
public static function rtrimImpl($str)
{
return rtrim($str);
}
public static function trimImpl($str)
{
return trim($str);
}
/**
* returns the regular expression operator
*
* @return string
*/
public function regexp()
{
return 'RLIKE';
}
/**
* soundex
* Returns a string to call a function to compute the
* soundex encoding of a string
*
* The string "?000" is returned if the argument is NULL.
*
* @param string $value
* @return string SQL soundex function with given parameter
*/
public function soundex($value)
{
return 'SOUNDEX(' . $value . ')';
}
/**
* Return string to call a variable with the current timestamp inside an SQL statement
* There are three special variables for current date and time.
*
* @return string sqlite function as string
*/
public function now($type = 'timestamp')
{
switch ($type) {
case 'time':
return 'time(\'now\')';
case 'date':
return 'date(\'now\')';
case 'timestamp':
default:
return 'datetime(\'now\')';
}
}
/**
* return string to call a function to get random value inside an SQL statement
*
* @return string to generate float between 0 and 1
*/
public function random()
{
return '((RANDOM() + 2147483648) / 4294967296)';
}
/**
* return string to call a function to get a substring inside an SQL statement
*
* Note: Not SQL92, but common functionality.
*
* SQLite only supports the 2 parameter variant of this function
*
* @param string $value an sql string literal or column name/alias
* @param integer $position where to start the substring portion
* @param integer $length the substring portion length
* @return string SQL substring function with given parameters
*/
public function substring($value, $position, $length = null)
{
if ($length !== null) {
return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')';
}
return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))';
}
} }
\ No newline at end of file
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
* @version $Revision: 3192 $ * @version $Revision: 3192 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @deprecated
*/ */
class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
{ {
......
...@@ -196,7 +196,8 @@ class Doctrine_Import extends Doctrine_Connection_Module ...@@ -196,7 +196,8 @@ class Doctrine_Import extends Doctrine_Connection_Module
* *
* @param string $directory * @param string $directory
* @param array $databases * @param array $databases
* @return array the names of the imported classes * @return array the names of the imported classes
* @todo ORM stuff
*/ */
public function importSchema($directory, array $databases = array(), array $options = array()) public function importSchema($directory, array $databases = array(), array $options = array())
{ {
......
...@@ -34,8 +34,6 @@ ...@@ -34,8 +34,6 @@
* Null object: Null valued of a field or empty association that has already been loaded. * Null object: Null valued of a field or empty association that has already been loaded.
* On access, the database is not queried. * On access, the database is not queried.
* *
* @package Doctrine
* @subpackage Null
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Really needed? Remove. * @todo Remove.
*/ */
interface Doctrine_Overloadable { interface Doctrine_Overloadable {
/** /**
......
...@@ -197,13 +197,13 @@ abstract class Doctrine_Query_Production ...@@ -197,13 +197,13 @@ abstract class Doctrine_Query_Production
* *
* @return string Sql piece * @return string Sql piece
*/ */
public function buildSql() /*public function buildSql()
{ {
$className = get_class($this); $className = get_class($this);
$methodName = substr($className, strrpos($className, '_')); $methodName = substr($className, strrpos($className, '_'));
$this->_sqlBuilder->$methodName($this); $this->_sqlBuilder->$methodName($this);
} }*/
/** /**
......
...@@ -73,7 +73,7 @@ class Doctrine_Query_Production_Atom extends Doctrine_Query_Production ...@@ -73,7 +73,7 @@ class Doctrine_Query_Production_Atom extends Doctrine_Query_Production
public function buildSql() public function buildSql()
{ {
$conn = $this->_parser->getSqlBuilder()->getConnection(); $conn = $this->_em->getConnection();
switch ($this->_type) { switch ($this->_type) {
case 'param': case 'param':
...@@ -86,7 +86,7 @@ class Doctrine_Query_Production_Atom extends Doctrine_Query_Production ...@@ -86,7 +86,7 @@ class Doctrine_Query_Production_Atom extends Doctrine_Query_Production
break; break;
default: default:
$stringQuoting = $conn->getProperty('string_quoting'); $stringQuoting = $conn->getDatabasePlatform()->getProperty('string_quoting');
return $stringQuoting['start'] return $stringQuoting['start']
. $conn->quote($this->_value, $this->_type) . $conn->quote($this->_value, $this->_type)
. $stringQuoting['end']; . $stringQuoting['end'];
......
...@@ -75,12 +75,7 @@ class Doctrine_Query_Production_IdentificationVariableDeclaration extends Doctri ...@@ -75,12 +75,7 @@ class Doctrine_Query_Production_IdentificationVariableDeclaration extends Doctri
$queryComponent = $parserResult->getQueryComponent($this->_rangeVariableDeclaration); $queryComponent = $parserResult->getQueryComponent($this->_rangeVariableDeclaration);
// Retrieving connection // Retrieving connection
$conn = $this->_parser->getSqlBuilder()->getConnection(); $conn = $this->_em->getConnection();
$manager = Doctrine_Manager::getInstance();
if ($manager->hasConnectionForComponent($queryComponent['metadata']->getClassName())) {
$conn = $manager->getConnectionForComponent($queryComponent['metadata']->getClassName());
}
$str = $conn->quoteIdentifier($queryComponent['metadata']->getTableName()) . ' ' $str = $conn->quoteIdentifier($queryComponent['metadata']->getTableName()) . ' '
. $conn->quoteIdentifier($parserResult->getTableAliasFromComponentAlias($this->_rangeVariableDeclaration)); . $conn->quoteIdentifier($parserResult->getTableAliasFromComponentAlias($this->_rangeVariableDeclaration));
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
* @link http://www.phpdoctrine.org * @link http://www.phpdoctrine.org
* @since 2.0 * @since 2.0
* @version $Revision$ * @version $Revision$
* @todo Merge into DatabasePlatform.
*/ */
abstract class Doctrine_Query_SqlBuilder abstract class Doctrine_Query_SqlBuilder
{ {
...@@ -83,198 +84,4 @@ abstract class Doctrine_Query_SqlBuilder ...@@ -83,198 +84,4 @@ abstract class Doctrine_Query_SqlBuilder
// End of Common SQL generations // End of Common SQL generations
/** The following is just test/draft code for now. */
/*private $_sql;
private $_conditionalTerms = array();
private $_conditionalFactors = array();
private $_conditionalPrimaries = array();
private $_variableDeclaration = array();
private $_expressions = array();
private $_deleteClause;
private $_whereClause;
public function visitVariableDeclaration($variableDeclaration)
{
echo " VariableDeclaration ";
// Basic handy variables
$parserResult = $variableDeclaration->getParser()->getParserResult();
$queryComponent = $parserResult->getQueryComponent($variableDeclaration->getComponentAlias());
// Retrieving connection
$manager = Doctrine_EntityManagerFactory::getManager();
$conn = $manager->getConnection();
$this->_variableDeclaration[] = $conn->quoteIdentifier($queryComponent['metadata']->getTableName()) . ' '
. $conn->quoteIdentifier($parserResult->getTableAliasFromComponentAlias(
$variableDeclaration->getComponentAlias()));
}
public function visitDeleteClause($deleteClause)
{
echo " DeleteClause ";
$this->_deleteClause = 'DELETE FROM ' . array_pop($this->_variableDeclaration);
}
public function visitDeleteStatement($deleteStatement)
{
echo " DeleteStatement ";
$this->_sql = $this->_deleteClause;
if ($this->_whereClause) {
$this->_sql .= $this->_whereClause;
} else {
$this->_sql .= " WHERE 1 = 1";
}
}
public function visitWhereClause($whereClause)
{
echo " WhereClause ";
if ($this->_expressions) {
$this->_whereClause = ' WHERE ' . array_pop($this->_expressions);
}
}
public function visitConditionalExpression($conditionalExpression)
{
echo " ConditionalExpression ";
$count = count($conditionalExpression->getConditionalTerms());
$terms = array();
for ($i=0; $i<$count; $i++) {
$terms[] = array_pop($this->_conditionalTerms);
}
$this->_expressions[] = implode(' OR ', $terms);
}
public function visitSimpleConditionalExpression($simpleConditionalExpression)
{
//var_dump($this->_expressions);
echo " SimpleConditionalExpression ";
$rightExpr = array_pop($this->_expressions);
$leftExpr = array_pop($this->_expressions);
$this->_expressions[] = $leftExpr . ' ' . $rightExpr;
}
public function visitConditionalPrimary($conditionalPrimary)
{
echo " ConditionalPrimary ";
if ($this->_expressions) {
$this->_conditionalPrimaries[] = '(' . array_pop($this->_expressions) . ')';
}
}
public function visitConditionalTerm($conditionalTerm)
{
echo " ConditionalTerm ";
$count = count($conditionalTerm->getConditionalFactors());
$factors = array();
for ($i=0; $i<$count; $i++) {
$factors[] = array_pop($this->_conditionalFactors);
}
$this->_conditionalTerms[] = implode(' AND ', $factors);
}
public function visitConditionalFactor($conditionalFactor)
{
echo " ConditionalFactor ";
if ($this->_conditionalPrimaries) {
$this->_conditionalFactors[] = 'NOT ' . array_pop($this->_conditionalPrimaries);
}
}
public function visitBetweenExpression($betweenExpression)
{
$this->_expressions[] = (($betweenExpression->getNot()) ? 'NOT ' : '') . 'BETWEEN '
. array_pop($this->_expressions) . ' AND ' . array_pop($this->_expressions);
}
public function visitLikeExpression($likeExpression)
{
$this->_expressions[] = (($likeExpression->getNot()) ? 'NOT ' : '') . 'LIKE ' .
array_pop($this->_expressions)
. (($likeExpression->getEscapeString() !== null) ? ' ESCAPE ' . $likeExpression->getEscapeString() : '');
}
public function visitInExpression($inExpression)
{
$count = count($inExpression->getAtoms());
$atoms = array();
for ($i=0; $i<$count; $i++) {
$atoms[] = array_pop($this->_expressions);
}
$this->_expressions[] = (($inExpression->getNot()) ? 'NOT ' : '') . 'IN ('
. (($inExpression->getSubselect() !== null) ? array_pop($this->_expressions) :
implode(', ', $atoms))
. ')';
}
public function visitNullComparisonExpression($nullComparisonExpression)
{
$this->_expressions[] = 'IS ' . (($nullComparisonExpression->getNot()) ? 'NOT ' : '') . 'NULL';
}
public function visitAtom($atom)
{
$conn = $atom->getParser()->getSqlBuilder()->getConnection();
switch ($atom->getType()) {
case 'param':
$this->_expressions[] = $atom->getValue();
break;
case 'integer':
case 'float':
$this->_expressions[] = $conn->quote($atom->getValue(), $atom->getType());
break;
default:
$stringQuoting = $this->_conn->getProperty('string_quoting');
$this->_expressions[] = $stringQuoting['start']
. $conn->quote($this->_value, $this->_type)
. $stringQuoting['end'];
break;
}
}
public function visitPathExpression($pathExpression)
{
echo " PathExpression ";
// Basic handy variables
$parserResult = $pathExpression->getParser()->getParserResult();
// Retrieving connection
$manager = Doctrine_EntityManagerFactory::getManager();
$conn = $manager->getConnection();
// Looking for queryComponent to fetch
$queryComponent = $parserResult->getQueryComponent($pathExpression->getComponentAlias());
// Generating the SQL piece
$str = $parserResult->getTableAliasFromComponentAlias($pathExpression->getComponentAlias()) . '.'
. $queryComponent['metadata']->getColumnName($pathExpression->getFieldName());
$this->_expressions[] = $conn->quoteIdentifier($str);
}
public function visitComparisonExpression($comparisonExpression)
{
echo " ComparisonExpression ";
$expr = $comparisonExpression->getOperator() . ' ';
if ($comparisonExpression->getIsSubselect()) {
$expr .= '(' . array_pop($this->_expressions) . ')';
} else {
$expr .= array_pop($this->_expressions);
}
$this->_expressions[] = $expr;
}
public function getSql()
{
return $this->_sql;
}*/
} }
...@@ -35,14 +35,7 @@ class Doctrine_Query_SqlExecutor_SingleTableDeleteUpdate extends Doctrine_Query_ ...@@ -35,14 +35,7 @@ class Doctrine_Query_SqlExecutor_SingleTableDeleteUpdate extends Doctrine_Query_
{ {
public function __construct(Doctrine_Query_Production $AST) public function __construct(Doctrine_Query_Production $AST)
{ {
parent::__construct($AST); parent::__construct($AST);
/*if ($AST instanceof Doctrine_Query_Production_DeleteStatement) {
$builder = new Doctrine_Query_SqlBuilder_MySql(Doctrine_EntityManagerFactory::getManager());
$AST->accept($builder);
echo PHP_EOL . "SQL:" . $builder->getSql() . PHP_EOL . PHP_EOL;
}*/
$this->_sqlStatements = $AST->buildSql(); $this->_sqlStatements = $AST->buildSql();
} }
......
...@@ -25,10 +25,9 @@ ...@@ -25,10 +25,9 @@
* Handles transaction savepoint and isolation abstraction * Handles transaction savepoint and isolation abstraction
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @package Doctrine
* @subpackage Transaction
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
...@@ -56,24 +55,6 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -56,24 +55,6 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
* transaction. * transaction.
*/ */
protected $_nestingLevel = 0; protected $_nestingLevel = 0;
/**
* @var integer $_internalNestingLevel The current internal nesting level of this transaction.
* "Internal" means transactions started by Doctrine itself.
* Therefore the internal nesting level is always
* lower or equal to the overall nesting level.
* A level of 0 means there is currently no active
* transaction that was initiated by Doctrine itself.
* @todo package:orm. I guess the DBAL does not start transactions on its own?
*/
protected $_internalNestingLevel = 0;
/**
* @var array $invalid an array containing all invalid records within this transaction
* @todo What about a more verbose name? $invalidRecords?
* package:orm
*/
protected $invalid = array();
/** /**
* @var array $savepoints an array containing all savepoints * @var array $savepoints an array containing all savepoints
...@@ -81,33 +62,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -81,33 +62,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
protected $savePoints = array(); protected $savePoints = array();
/** /**
* @var array $_collections an array of Doctrine_Collection objects that were affected during the Transaction * Returns the state of this transaction module.
* @todo package:orm
*/
protected $_collections = array();
/**
* addCollection
* adds a collection in the internal array of collections
*
* at the end of each commit this array is looped over and
* of every collection Doctrine then takes a snapshot in order
* to keep the collections up to date with the database
*
* @param Doctrine_Collection $coll a collection to be added
* @return Doctrine_Transaction this object
* @todo package:orm
*/
public function addCollection(Doctrine_Collection $coll)
{
$this->_collections[] = $coll;
return $this;
}
/**
* getState
* returns the state of this transaction module.
* *
* @see Doctrine_Connection_Transaction::STATE_* constants * @see Doctrine_Connection_Transaction::STATE_* constants
* @return integer the connection state * @return integer the connection state
...@@ -116,49 +71,18 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -116,49 +71,18 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
{ {
switch ($this->_nestingLevel) { switch ($this->_nestingLevel) {
case 0: case 0:
return Doctrine_Transaction::STATE_SLEEP; return self::STATE_SLEEP;
break; break;
case 1: case 1:
return Doctrine_Transaction::STATE_ACTIVE; return self::STATE_ACTIVE;
break; break;
default: default:
return Doctrine_Transaction::STATE_BUSY; return self::STATE_BUSY;
} }
} }
/** /**
* addInvalid * Gets the current transaction nesting level.
* adds record into invalid records list
*
* @param Doctrine_Entity $record
* @return boolean false if record already existed in invalid records list,
* otherwise true
* @todo package:orm
*/
public function addInvalid(Doctrine_Entity $record)
{
if (in_array($record, $this->invalid, true)) {
return false;
}
$this->invalid[] = $record;
return true;
}
/**
* Return the invalid records
*
* @return array An array of invalid records
* @todo package:orm
*/
public function getInvalid()
{
return $this->invalid;
}
/**
* getTransactionLevel
* get the current transaction nesting level
* *
* @return integer * @return integer
* @todo Name suggestion: getNestingLevel(). $transaction->getTransactionLevel() looks odd. * @todo Name suggestion: getNestingLevel(). $transaction->getTransactionLevel() looks odd.
...@@ -167,21 +91,8 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -167,21 +91,8 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
{ {
return $this->_nestingLevel; return $this->_nestingLevel;
} }
/**
* getInternalTransactionLevel
* get the current internal transaction nesting level
*
* @return integer
* @todo package:orm. I guess the DBAL does not start transactions itself?
*/
public function getInternalTransactionLevel()
{
return $this->_internalNestingLevel;
}
/** /**
* beginTransaction
* Start a transaction or set a savepoint. * Start a transaction or set a savepoint.
* *
* if trying to set a savepoint and there is no active transaction * if trying to set a savepoint and there is no active transaction
...@@ -195,40 +106,33 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -195,40 +106,33 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
* @param string $savepoint name of a savepoint to set * @param string $savepoint name of a savepoint to set
* @throws Doctrine_Transaction_Exception if the transaction fails at database level * @throws Doctrine_Transaction_Exception if the transaction fails at database level
* @return integer current transaction nesting level * @return integer current transaction nesting level
* @todo Name suggestion: begin(). $transaction->beginTransaction() looks odd.
*/ */
public function beginTransaction($savepoint = null) public function begin($savepoint = null)
{ {
$this->conn->connect(); $this->conn->connect();
//$listener = $this->conn->getAttribute(Doctrine::ATTR_LISTENER);
$listener = $this->conn->getAttribute(Doctrine::ATTR_LISTENER);
if ( ! is_null($savepoint)) { if ( ! is_null($savepoint)) {
$this->savePoints[] = $savepoint; $this->savePoints[] = $savepoint;
//$event = new Doctrine_Event($this, Doctrine_Event::SAVEPOINT_CREATE);
$event = new Doctrine_Event($this, Doctrine_Event::SAVEPOINT_CREATE); //$listener->preSavepointCreate($event);
//if ( ! $event->skipOperation) {
$listener->preSavepointCreate($event);
if ( ! $event->skipOperation) {
$this->createSavePoint($savepoint); $this->createSavePoint($savepoint);
} //}
//$listener->postSavepointCreate($event);
$listener->postSavepointCreate($event);
} else { } else {
if ($this->_nestingLevel == 0) { if ($this->_nestingLevel == 0) {
$event = new Doctrine_Event($this, Doctrine_Event::TX_BEGIN); //$event = new Doctrine_Event($this, Doctrine_Event::TX_BEGIN);
//$listener->preTransactionBegin($event);
$listener->preTransactionBegin($event);
if ( ! $event->skipOperation) { //if ( ! $event->skipOperation) {
try { try {
$this->_doBeginTransaction(); $this->_doBeginTransaction();
} catch (Exception $e) { } catch (Exception $e) {
throw new Doctrine_Transaction_Exception($e->getMessage()); throw new Doctrine_Transaction_Exception($e->getMessage());
} }
} //}
$listener->postTransactionBegin($event); //$listener->postTransactionBegin($event);
} }
} }
...@@ -238,8 +142,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -238,8 +142,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
} }
/** /**
* commit * Commits the database changes done during a transaction that is in
* Commit the database changes done during a transaction that is in
* progress or release a savepoint. This function may only be called when * progress or release a savepoint. This function may only be called when
* auto-committing is disabled, otherwise it will fail. * auto-committing is disabled, otherwise it will fail.
* *
...@@ -258,60 +161,35 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -258,60 +161,35 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
$this->conn->connect(); $this->conn->connect();
$listener = $this->conn->getAttribute(Doctrine::ATTR_LISTENER); //$listener = $this->conn->getAttribute(Doctrine::ATTR_LISTENER);
if ( ! is_null($savepoint)) { if ( ! is_null($savepoint)) {
$this->_nestingLevel -= $this->removeSavePoints($savepoint); $this->_nestingLevel -= $this->removeSavePoints($savepoint);
//$event = new Doctrine_Event($this, Doctrine_Event::SAVEPOINT_COMMIT);
$event = new Doctrine_Event($this, Doctrine_Event::SAVEPOINT_COMMIT); //$listener->preSavepointCommit($event);
//if ( ! $event->skipOperation) {
$listener->preSavepointCommit($event);
if ( ! $event->skipOperation) {
$this->releaseSavePoint($savepoint); $this->releaseSavePoint($savepoint);
} //}
//$listener->postSavepointCommit($event);
$listener->postSavepointCommit($event); } else {
} else { if ($this->_nestingLevel == 1) {
//$event = new Doctrine_Event($this, Doctrine_Event::TX_COMMIT);
if ($this->_nestingLevel == 1 || $this->_internalNestingLevel == 1) { //$listener->preTransactionCommit($event);
if ( ! empty($this->invalid)) { //if ( ! $event->skipOperation) {
if ($this->_internalNestingLevel == 1) { $this->_doCommit();
$tmp = $this->invalid; //}
$this->invalid = array(); //$listener->postTransactionCommit($event);
throw new Doctrine_Validator_Exception($tmp);
}
}
if ($this->_nestingLevel == 1) {
// take snapshots of all collections used within this transaction
foreach ($this->_collections as $coll) {
$coll->takeSnapshot();
}
$this->_collections = array();
$event = new Doctrine_Event($this, Doctrine_Event::TX_COMMIT);
$listener->preTransactionCommit($event);
if ( ! $event->skipOperation) {
$this->_doCommit();
}
$listener->postTransactionCommit($event);
}
} }
if ($this->_nestingLevel > 0) { if ($this->_nestingLevel > 0) {
$this->_nestingLevel--; $this->_nestingLevel--;
} }
if ($this->_internalNestingLevel > 0) {
$this->_internalNestingLevel--;
}
} }
return true; return true;
} }
/** /**
* rollback
* Cancel any database changes done during a transaction or since a specific * Cancel any database changes done during a transaction or since a specific
* savepoint that is in progress. This function may only be called when * savepoint that is in progress. This function may only be called when
* auto-committing is disabled, otherwise it will fail. Therefore, a new * auto-committing is disabled, otherwise it will fail. Therefore, a new
...@@ -332,8 +210,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -332,8 +210,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
$this->conn->connect(); $this->conn->connect();
if ($this->_internalNestingLevel > 1 || $this->_nestingLevel > 1) { if ($this->_nestingLevel > 1) {
$this->_internalNestingLevel--;
$this->_nestingLevel--; $this->_nestingLevel--;
return false; return false;
} }
...@@ -342,34 +219,31 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -342,34 +219,31 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
if ( ! is_null($savepoint)) { if ( ! is_null($savepoint)) {
$this->_nestingLevel -= $this->removeSavePoints($savepoint); $this->_nestingLevel -= $this->removeSavePoints($savepoint);
$event = new Doctrine_Event($this, Doctrine_Event::SAVEPOINT_ROLLBACK); //$event = new Doctrine_Event($this, Doctrine_Event::SAVEPOINT_ROLLBACK);
$listener->preSavepointRollback($event); //$listener->preSavepointRollback($event);
if ( ! $event->skipOperation) { //if ( ! $event->skipOperation) {
$this->rollbackSavePoint($savepoint); $this->rollbackSavePoint($savepoint);
} //}
$listener->postSavepointRollback($event); //$listener->postSavepointRollback($event);
} else { } else {
$event = new Doctrine_Event($this, Doctrine_Event::TX_ROLLBACK); //$event = new Doctrine_Event($this, Doctrine_Event::TX_ROLLBACK);
$listener->preTransactionRollback($event); //$listener->preTransactionRollback($event);
//if ( ! $event->skipOperation) {
if ( ! $event->skipOperation) {
$this->_nestingLevel = 0; $this->_nestingLevel = 0;
$this->_internalNestingLevel = 0;
try { try {
$this->_doRollback(); $this->_doRollback();
} catch (Exception $e) { } catch (Exception $e) {
throw new Doctrine_Transaction_Exception($e->getMessage()); throw new Doctrine_Transaction_Exception($e->getMessage());
} }
} //}
$listener->postTransactionRollback($event); //$listener->postTransactionRollback($event);
} }
return true; return true;
} }
/** /**
* releaseSavePoint * Creates a new savepoint.
* creates a new savepoint
* *
* @param string $savepoint name of a savepoint to create * @param string $savepoint name of a savepoint to create
* @return void * @return void
...@@ -380,8 +254,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -380,8 +254,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
} }
/** /**
* releaseSavePoint * Releases given savepoint.
* releases given savepoint
* *
* @param string $savepoint name of a savepoint to release * @param string $savepoint name of a savepoint to release
* @return void * @return void
...@@ -392,8 +265,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -392,8 +265,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
} }
/** /**
* rollbackSavePoint * Performs a rollback to a specified savepoint.
* releases given savepoint
* *
* @param string $savepoint name of a savepoint to rollback to * @param string $savepoint name of a savepoint to rollback to
* @return void * @return void
...@@ -428,7 +300,6 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -428,7 +300,6 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
} }
/** /**
* removeSavePoints
* removes a savepoint from the internal savePoints array of this transaction object * removes a savepoint from the internal savePoints array of this transaction object
* and all its children savepoints * and all its children savepoints
* *
...@@ -458,8 +329,6 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -458,8 +329,6 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
} }
/** /**
* setIsolation
*
* Set the transacton isolation level. * Set the transacton isolation level.
* (implemented by the connection drivers) * (implemented by the connection drivers)
* *
...@@ -485,9 +354,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -485,9 +354,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
} }
/** /**
* getTransactionIsolation * Fetches the current session transaction isolation level.
*
* fetches the current session transaction isolation level
* *
* note: some drivers may support setting the transaction isolation level * note: some drivers may support setting the transaction isolation level
* but not fetching it * but not fetching it
...@@ -499,18 +366,5 @@ class Doctrine_Transaction extends Doctrine_Connection_Module ...@@ -499,18 +366,5 @@ class Doctrine_Transaction extends Doctrine_Connection_Module
public function getIsolation() public function getIsolation()
{ {
throw new Doctrine_Transaction_Exception('Fetching transaction isolation level not supported by this driver.'); throw new Doctrine_Transaction_Exception('Fetching transaction isolation level not supported by this driver.');
} }
/**
* Initiates a transaction.
*
* This method must only be used by Doctrine itself to initiate transactions.
* Userland-code must use {@link beginTransaction()}.
*/
public function beginInternalTransaction($savepoint = null)
{
$this->_internalNestingLevel++;
return $this->beginTransaction($savepoint);
}
} }
...@@ -18,14 +18,14 @@ ...@@ -18,14 +18,14 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Transaction');
#namespace Doctrine::DBAL::Transactions;
/** /**
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @package Doctrine
* @subpackage Transaction
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
...@@ -33,11 +33,11 @@ Doctrine::autoload('Doctrine_Transaction'); ...@@ -33,11 +33,11 @@ Doctrine::autoload('Doctrine_Transaction');
class Doctrine_Transaction_Firebird extends Doctrine_Transaction class Doctrine_Transaction_Firebird extends Doctrine_Transaction
{ {
/** /**
* createSavepoint
* creates a new savepoint * creates a new savepoint
* *
* @param string $savepoint name of a savepoint to set * @param string $savepoint name of a savepoint to set
* @return void * @return void
* @override
*/ */
protected function createSavePoint($savepoint) protected function createSavePoint($savepoint)
{ {
...@@ -47,11 +47,11 @@ class Doctrine_Transaction_Firebird extends Doctrine_Transaction ...@@ -47,11 +47,11 @@ class Doctrine_Transaction_Firebird extends Doctrine_Transaction
} }
/** /**
* releaseSavePoint
* releases given savepoint * releases given savepoint
* *
* @param string $savepoint name of a savepoint to release * @param string $savepoint name of a savepoint to release
* @return void * @return void
* @override
*/ */
protected function releaseSavePoint($savepoint) protected function releaseSavePoint($savepoint)
{ {
...@@ -61,11 +61,11 @@ class Doctrine_Transaction_Firebird extends Doctrine_Transaction ...@@ -61,11 +61,11 @@ class Doctrine_Transaction_Firebird extends Doctrine_Transaction
} }
/** /**
* rollbackSavePoint
* releases given savepoint * releases given savepoint
* *
* @param string $savepoint name of a savepoint to rollback to * @param string $savepoint name of a savepoint to rollback to
* @return void * @return void
* @override
*/ */
protected function rollbackSavePoint($savepoint) protected function rollbackSavePoint($savepoint)
{ {
...@@ -89,7 +89,8 @@ class Doctrine_Transaction_Firebird extends Doctrine_Transaction ...@@ -89,7 +89,8 @@ class Doctrine_Transaction_Firebird extends Doctrine_Transaction
* *
* @throws PDOException if something fails at the PDO level * @throws PDOException if something fails at the PDO level
* @throws Doctrine_Transaction_Exception if using unknown isolation level or unknown wait option * @throws Doctrine_Transaction_Exception if using unknown isolation level or unknown wait option
* @return void * @return void
* @override
*/ */
public function setIsolation($isolation, $options = array()) { public function setIsolation($isolation, $options = array()) {
switch ($isolation) { switch ($isolation) {
......
...@@ -18,14 +18,12 @@ ...@@ -18,14 +18,12 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Transaction');
/** /**
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @package Doctrine
* @subpackage Transaction
* @link www.phpdoctrine.org * @link www.phpdoctrine.org
* @since 1.0 * @since 1.0
* @version $Revision$ * @version $Revision$
......
...@@ -47,7 +47,8 @@ class Doctrine_Transaction_Mssql extends Doctrine_Transaction ...@@ -47,7 +47,8 @@ class Doctrine_Transaction_Mssql extends Doctrine_Transaction
* @link http://msdn2.microsoft.com/en-us/library/ms173763.aspx * @link http://msdn2.microsoft.com/en-us/library/ms173763.aspx
* @throws PDOException if something fails at the PDO level * @throws PDOException if something fails at the PDO level
* @throws Doctrine_Transaction_Exception if using unknown isolation level or unknown wait option * @throws Doctrine_Transaction_Exception if using unknown isolation level or unknown wait option
* @return void * @return void
* @override
*/ */
public function setIsolation($isolation, $options = array()) { public function setIsolation($isolation, $options = array()) {
switch ($isolation) { switch ($isolation) {
...@@ -67,7 +68,9 @@ class Doctrine_Transaction_Mssql extends Doctrine_Transaction ...@@ -67,7 +68,9 @@ class Doctrine_Transaction_Mssql extends Doctrine_Transaction
} }
/** /**
* Performs the rollback. * Performs the rollback.
*
* @override
*/ */
protected function _doRollback() protected function _doRollback()
{ {
...@@ -75,7 +78,9 @@ class Doctrine_Transaction_Mssql extends Doctrine_Transaction ...@@ -75,7 +78,9 @@ class Doctrine_Transaction_Mssql extends Doctrine_Transaction
} }
/** /**
* Performs the commit. * Performs the commit.
*
* @override
*/ */
protected function _doCommit() protected function _doCommit()
{ {
...@@ -83,7 +88,9 @@ class Doctrine_Transaction_Mssql extends Doctrine_Transaction ...@@ -83,7 +88,9 @@ class Doctrine_Transaction_Mssql extends Doctrine_Transaction
} }
/** /**
* Begins a database transaction. * Begins a database transaction.
*
* @override
*/ */
protected function _doBeginTransaction() protected function _doBeginTransaction()
{ {
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Transaction');
/** /**
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Transaction');
/** /**
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
...@@ -33,11 +33,11 @@ Doctrine::autoload('Doctrine_Transaction'); ...@@ -33,11 +33,11 @@ Doctrine::autoload('Doctrine_Transaction');
class Doctrine_Transaction_Oracle extends Doctrine_Transaction class Doctrine_Transaction_Oracle extends Doctrine_Transaction
{ {
/** /**
* createSavepoint
* creates a new savepoint * creates a new savepoint
* *
* @param string $savepoint name of a savepoint to set * @param string $savepoint name of a savepoint to set
* @return void * @return void
* @override
*/ */
protected function createSavePoint($savepoint) protected function createSavePoint($savepoint)
{ {
...@@ -47,11 +47,11 @@ class Doctrine_Transaction_Oracle extends Doctrine_Transaction ...@@ -47,11 +47,11 @@ class Doctrine_Transaction_Oracle extends Doctrine_Transaction
} }
/** /**
* releaseSavePoint
* releases given savepoint * releases given savepoint
* *
* @param string $savepoint name of a savepoint to release * @param string $savepoint name of a savepoint to release
* @return void * @return void
* @override
*/ */
protected function releaseSavePoint($savepoint) protected function releaseSavePoint($savepoint)
{ {
...@@ -60,11 +60,11 @@ class Doctrine_Transaction_Oracle extends Doctrine_Transaction ...@@ -60,11 +60,11 @@ class Doctrine_Transaction_Oracle extends Doctrine_Transaction
} }
/** /**
* rollbackSavePoint
* releases given savepoint * releases given savepoint
* *
* @param string $savepoint name of a savepoint to rollback to * @param string $savepoint name of a savepoint to rollback to
* @return void * @return void
* @override
*/ */
protected function rollbackSavePoint($savepoint) protected function rollbackSavePoint($savepoint)
{ {
...@@ -83,7 +83,8 @@ class Doctrine_Transaction_Oracle extends Doctrine_Transaction ...@@ -83,7 +83,8 @@ class Doctrine_Transaction_Oracle extends Doctrine_Transaction
* SERIALIZABLE (prevents phantom reads) * SERIALIZABLE (prevents phantom reads)
* @throws PDOException if something fails at the PDO level * @throws PDOException if something fails at the PDO level
* @throws Doctrine_Transaction_Exception if using unknown isolation level * @throws Doctrine_Transaction_Exception if using unknown isolation level
* @return void * @return void
* @override
*/ */
public function setIsolation($isolation) public function setIsolation($isolation)
{ {
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Transaction');
/** /**
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
...@@ -38,7 +38,8 @@ class Doctrine_Transaction_Pgsql extends Doctrine_Transaction ...@@ -38,7 +38,8 @@ class Doctrine_Transaction_Pgsql extends Doctrine_Transaction
* creates a new savepoint * creates a new savepoint
* *
* @param string $savepoint name of a savepoint to set * @param string $savepoint name of a savepoint to set
* @return void * @return void
* @override
*/ */
protected function createSavePoint($savepoint) protected function createSavePoint($savepoint)
{ {
...@@ -52,7 +53,8 @@ class Doctrine_Transaction_Pgsql extends Doctrine_Transaction ...@@ -52,7 +53,8 @@ class Doctrine_Transaction_Pgsql extends Doctrine_Transaction
* releases given savepoint * releases given savepoint
* *
* @param string $savepoint name of a savepoint to release * @param string $savepoint name of a savepoint to release
* @return void * @return void
* @override
*/ */
protected function releaseSavePoint($savepoint) protected function releaseSavePoint($savepoint)
{ {
...@@ -66,7 +68,8 @@ class Doctrine_Transaction_Pgsql extends Doctrine_Transaction ...@@ -66,7 +68,8 @@ class Doctrine_Transaction_Pgsql extends Doctrine_Transaction
* releases given savepoint * releases given savepoint
* *
* @param string $savepoint name of a savepoint to rollback to * @param string $savepoint name of a savepoint to rollback to
* @return void * @return void
* @override
*/ */
protected function rollbackSavePoint($savepoint) protected function rollbackSavePoint($savepoint)
{ {
...@@ -85,7 +88,8 @@ class Doctrine_Transaction_Pgsql extends Doctrine_Transaction ...@@ -85,7 +88,8 @@ class Doctrine_Transaction_Pgsql extends Doctrine_Transaction
* SERIALIZABLE (prevents phantom reads) * SERIALIZABLE (prevents phantom reads)
* @throws PDOException if something fails at the PDO level * @throws PDOException if something fails at the PDO level
* @throws Doctrine_Transaction_Exception if using unknown isolation level or unknown wait option * @throws Doctrine_Transaction_Exception if using unknown isolation level or unknown wait option
* @return void * @return void
* @override
*/ */
public function setIsolation($isolation) public function setIsolation($isolation)
{ {
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.phpdoctrine.org>.
*/ */
Doctrine::autoload('Doctrine_Transaction');
/** /**
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
...@@ -42,7 +42,8 @@ class Doctrine_Transaction_Sqlite extends Doctrine_Transaction ...@@ -42,7 +42,8 @@ class Doctrine_Transaction_Sqlite extends Doctrine_Transaction
* SERIALIZABLE (prevents phantom reads) * SERIALIZABLE (prevents phantom reads)
* @throws PDOException if something fails at the PDO level * @throws PDOException if something fails at the PDO level
* @throws Doctrine_Transaction_Exception if using unknown isolation level * @throws Doctrine_Transaction_Exception if using unknown isolation level
* @return void * @return void
* @override
*/ */
public function setIsolation($isolation) public function setIsolation($isolation)
{ {
......
<?php
require_once 'lib/DoctrineTestInit.php';
/**
* Tests of the commit order calculation.
*
* IMPORTANT: When writing tests here consider that a lot of graph constellations
* can have many valid orderings, so you may want to build a graph that has only
* 1 valid order to simplify your tests.
*/
class Orm_Internal_CommitOrderCalculatorTest extends Doctrine_OrmTestCase
{
private $_calc;
protected function setUp()
{
$this->_calc = new Doctrine_Internal_CommitOrderCalculator();
}
private function _createNodes(array $names)
{
$nodes = array();
foreach ($names as $name) {
$node = new Doctrine_Internal_CommitOrderNode($name, $this->_calc);
$nodes[$name] = $node;
$this->_calc->addNode($node->getClass(), $node);
}
return $nodes;
}
public function testCommitOrdering1()
{
$nodes = $this->_createNodes(array("node1", "node2", "node3", "node4", "node5"));
$nodes['node1']->before($nodes['node2']);
$nodes['node2']->before($nodes['node3']);
$nodes['node3']->before($nodes['node4']);
$nodes['node5']->before($nodes['node1']);
shuffle($nodes); // some randomness
$sorted = $this->_calc->getCommitOrder();
// There is only 1 valid ordering for this constellation
$correctOrder = array("node5", "node1", "node2", "node3", "node4");
$this->assertSame($correctOrder, $sorted);
}
}
...@@ -23,6 +23,7 @@ class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase ...@@ -23,6 +23,7 @@ class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase
private $_persisterMock; private $_persisterMock;
// The EntityManager mock that provides the mock persister // The EntityManager mock that provides the mock persister
private $_emMock; private $_emMock;
private $_platformMock;
protected function setUp() { protected function setUp() {
parent::setUp(); parent::setUp();
...@@ -32,9 +33,17 @@ class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase ...@@ -32,9 +33,17 @@ class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase
$this->_user->username = 'romanb'; $this->_user->username = 'romanb';
$this->_connectionMock = new Doctrine_ConnectionMock(array()); $this->_connectionMock = new Doctrine_ConnectionMock(array());
$this->_sequenceMock = $this->_connectionMock->getSequenceManager(); $this->_platformMock = new Doctrine_DatabasePlatformMock();
$this->_emMock = new Doctrine_EntityManagerMock($this->_connectionMock); $this->_emMock = new Doctrine_EntityManagerMock($this->_connectionMock);
$this->_persisterMock = $this->_emMock->getEntityPersister("ForumUser"); $this->_sequenceMock = new Doctrine_SequenceMock($this->_connectionMock);
$this->_connectionMock->setSequenceManager($this->_sequenceMock);
$this->_connectionMock->setDatabasePlatform($this->_platformMock);
$this->_persisterMock = new Doctrine_EntityPersisterMock(
$this->_emMock, $this->_emMock->getClassMetadata("ForumUser"));
$this->_emMock->setEntityPersister($this->_persisterMock);
$this->_unitOfWork = $this->_emMock->getUnitOfWork(); $this->_unitOfWork = $this->_emMock->getUnitOfWork();
} }
...@@ -105,7 +114,7 @@ class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase ...@@ -105,7 +114,7 @@ class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase
// should have an id // should have an id
$this->assertTrue(is_numeric($this->_user->id)); $this->assertTrue(is_numeric($this->_user->id));
// Now lets check whether a subsequence commit() does anything // Now lets check whether a subsequent commit() does anything
$this->_persisterMock->reset(); $this->_persisterMock->reset();
......
<?php <?php
require_once 'lib/mocks/Doctrine_SequenceMock.php'; require_once 'lib/mocks/Doctrine_SequenceMock.php';
require_once 'lib/mocks/Doctrine_DatabasePlatformMock.php';
class Doctrine_ConnectionMock extends Doctrine_Connection class Doctrine_ConnectionMock extends Doctrine_Connection
{ {
protected $_driverName = 'Mysql'; protected $_driverName = 'Mock';
private $_sequenceModuleMock; private $_sequenceModuleMock;
private $_platformMock;
public function __construct(array $params)
{
parent::__construct($params);
}
/**
* @override
*/
public function getSequenceManager() public function getSequenceManager()
{ {
if ( ! $this->_sequenceModuleMock) {
$this->_sequenceModuleMock = new Doctrine_SequenceMock($this);
}
return $this->_sequenceModuleMock; return $this->_sequenceModuleMock;
} }
/**
* @override
*/
public function getDatabasePlatform()
{
return $this->_platformMock;
}
/* Mock API */
public function setDatabasePlatform($platform)
{
$this->_platformMock = $platform;
}
public function setSequenceManager($seqManager)
{
$this->_sequenceModuleMock = $seqManager;
}
} }
?> ?>
\ No newline at end of file
<?php
class Doctrine_DatabasePlatformMock extends Doctrine_DatabasePlatform
{
public function getNativeDeclaration($field) {}
public function getPortableDeclaration(array $field) {}
}
?>
\ No newline at end of file
...@@ -6,7 +6,6 @@ class Doctrine_EntityManagerMock extends Doctrine_EntityManager ...@@ -6,7 +6,6 @@ class Doctrine_EntityManagerMock extends Doctrine_EntityManager
{ {
private $_persisterMock; private $_persisterMock;
/** /**
* Enter description here... * Enter description here...
* *
...@@ -15,11 +14,15 @@ class Doctrine_EntityManagerMock extends Doctrine_EntityManager ...@@ -15,11 +14,15 @@ class Doctrine_EntityManagerMock extends Doctrine_EntityManager
*/ */
public function getEntityPersister($entityName) public function getEntityPersister($entityName)
{ {
if ( ! $this->_persisterMock) {
$this->_persisterMock = new Doctrine_EntityPersisterMock($this, $this->getClassMetadata($entityName));
}
return $this->_persisterMock; return $this->_persisterMock;
} }
/* Mock API */
public function setEntityPersister($persister)
{
$this->_persisterMock = $persister;
}
} }
?> ?>
\ No newline at end of file
...@@ -28,6 +28,8 @@ class Doctrine_SequenceMock extends Doctrine_Sequence ...@@ -28,6 +28,8 @@ class Doctrine_SequenceMock extends Doctrine_Sequence
return $this->_sequenceNumber; return $this->_sequenceNumber;
} }
/* Mock API */
public function reset() public function reset()
{ {
$this->_sequenceNumber = 0; $this->_sequenceNumber = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment