diff --git a/lib/Doctrine/Connection.php b/lib/Doctrine/Connection.php index 5629adecf..1e8951540 100644 --- a/lib/Doctrine/Connection.php +++ b/lib/Doctrine/Connection.php @@ -50,8 +50,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun * one of the following (true, false, 'emulated') */ protected $supported = array(); - - protected $options = array(); /** * @var array $modules an array containing all modules * transaction Doctrine_Transaction driver, handles savepoint and transaction isolation abstraction @@ -75,6 +73,10 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun 'export' => false, 'unitOfWork' => false, ); + /** + * @var array $properties an array of connection properties + */ + protected $properties = array(); /** * @var array $availibleDrivers an array containing all availible drivers */ @@ -145,7 +147,10 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun $class = 'Doctrine_' . ucwords($name) . '_' . $this->getName(); $this->modules[$name] = new $class($this); } - } + } + if(isset($this->properties[$name])) + return $this->properties[$name]; + return $this->modules[$name]; } @@ -206,9 +211,12 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun if ($checkOption && ! $this->getAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER)) { return $str; } - return $str; - //$str = str_replace($this->identifier_quoting['end'], $this->identifier_quoting['escape'] . $this->identifier_quoting['end'], $str); - //return $this->identifier_quoting['start'] . $str . $this->identifier_quoting['end']; + $str = str_replace($this->properties['identifier_quoting']['end'], + $this->properties['identifier_quoting']['escape'] . + $this->properties['identifier_quoting']['end'], $str); + + return $this->properties['identifier_quoting']['start'] + . $str . $this->properties['identifier_quoting']['end']; } /** * returns the manager that created this connection @@ -291,7 +299,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun */ public function getIndexName($idx) { return sprintf($this->getAttribute(Doctrine::ATTR_IDXNAME_FORMAT), - preg_replace('/[^a-z0-9_\$]/i', '_', $idx)); + preg_replace('/[^a-z0-9_\$]/i', '_', $idx)); } /** diff --git a/lib/Doctrine/Connection/Mysql.php b/lib/Doctrine/Connection/Mysql.php index 391be15bc..e95f12131 100644 --- a/lib/Doctrine/Connection/Mysql.php +++ b/lib/Doctrine/Connection/Mysql.php @@ -65,9 +65,26 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common { '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($manager, $adapter); - } + } /** * Returns the next free id of a sequence * @@ -103,7 +120,7 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common { $sequenceName = $this->quoteIdentifier($this->getSequenceName($seqName), true); $seqcolName = $this->quoteIdentifier($this->options['seqcol_name'], true); $query = 'SELECT MAX(' . $seqcolName . ') FROM ' . $sequenceName; - return $this->queryOne($query, 'integer'); + return $this->fetchOne($query); } /** * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT diff --git a/lib/Doctrine/Connection/Pgsql.php b/lib/Doctrine/Connection/Pgsql.php index fe6e24117..cff36860c 100644 --- a/lib/Doctrine/Connection/Pgsql.php +++ b/lib/Doctrine/Connection/Pgsql.php @@ -65,8 +65,6 @@ class Doctrine_Connection_Pgsql extends Doctrine_Connection_Common { 'pattern_escaping' => true, ); - $this->options['multi_query'] = false; - parent::__construct($manager, $adapter); } /** diff --git a/lib/Doctrine/DataDict.php b/lib/Doctrine/DataDict.php index 05cac5a01..cb428799f 100644 --- a/lib/Doctrine/DataDict.php +++ b/lib/Doctrine/DataDict.php @@ -21,19 +21,20 @@ /** * Doctrine_DataDict * - * @package Doctrine - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @category Object Relational Mapping - * @link www.phpdoctrine.com - * @since 1.0 - * @version $Revision$ - * @author Konsta Vesterinen - */ + * @package Doctrine + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + * @author Konsta Vesterinen + */ class Doctrine_DataDict { protected $dbh; public function __construct($dbh = null) { + $file = Doctrine::getPath().DIRECTORY_SEPARATOR."Doctrine".DIRECTORY_SEPARATOR."adodb-hack".DIRECTORY_SEPARATOR."adodb.inc.php"; if( ! file_exists($file)) diff --git a/lib/Doctrine/DataDict/Mysql.php b/lib/Doctrine/DataDict/Mysql.php index ff57303db..aeb383845 100644 --- a/lib/Doctrine/DataDict/Mysql.php +++ b/lib/Doctrine/DataDict/Mysql.php @@ -29,7 +29,7 @@ Doctrine::autoload('Doctrine_DataDict'); * @link www.phpdoctrine.com * @since 1.0 */ -class Doctrine_DataDict_Mysql extends Doctrine_DataDict { +class Doctrine_DataDict_Mysql extends Doctrine_Connection_Module { /** * Obtain DBMS specific SQL code portion needed to declare an text type * field to be used in statements like CREATE TABLE. @@ -55,6 +55,11 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict { */ public function getNativeDeclaration($field) { 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': @@ -321,12 +326,15 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict { $field['default'] = empty($field['notnull']) ? null : 0; } $default = ' DEFAULT '.$this->conn->getDbh()->quote($field['default']); - } elseif (empty($field['notnull'])) { + } + /** + elseif (empty($field['notnull'])) { $default = ' DEFAULT NULL'; } + */ - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED'; + $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; + $unsigned = (isset($field['unsigned']) && $field['unsigned']) ? ' UNSIGNED' : ''; $name = $this->conn->quoteIdentifier($name, true); diff --git a/lib/Doctrine/DataDict/Pgsql.php b/lib/Doctrine/DataDict/Pgsql.php index 540b9154e..4dae75fc1 100644 --- a/lib/Doctrine/DataDict/Pgsql.php +++ b/lib/Doctrine/DataDict/Pgsql.php @@ -357,15 +357,15 @@ class Doctrine_DataDict_Pgsql extends Doctrine_Connection_Module { */ public function getNativeDeclaration(array $field) { switch ($field['type']) { + case 'char': case 'string': case 'array': case 'object': case 'varchar': - case 'char': - $length = !empty($field['length']) - ? $field['length'] : $db->options['default_text_field_length']; + $length = (isset($field['length']) && $field['length']) ? $field['length'] : null; + // TODO: $db->options['default_text_field_length']; - $fixed = !empty($field['fixed']) ? $field['fixed'] : false; + $fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false; return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')') : ($length ? 'VARCHAR('.$length.')' : 'TEXT'); @@ -413,16 +413,16 @@ class Doctrine_DataDict_Pgsql extends Doctrine_Connection_Module { } } /** - * Maps a native array description of a field to a MDB2 datatype and length + * 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 getDoctrineDeclaration(array $field) { + public function getPortableDeclaration(array $field) { $length = $field['length']; - if ($length == '-1' && !empty($field['atttypmod'])) { + if ($length == '-1' && isset($field['atttypmod'])) { $length = $field['atttypmod'] - 4; } if ((int)$length <= 0) { diff --git a/lib/Doctrine/Export.php b/lib/Doctrine/Export.php index fb1bab7b3..326d9f7e7 100644 --- a/lib/Doctrine/Export.php +++ b/lib/Doctrine/Export.php @@ -347,11 +347,102 @@ class Doctrine_Export extends Doctrine_Connection_Module { * @return string */ public function getFieldDeclarationList(array $fields) { - foreach ($fields as $field_name => $field) { - $query = $this->conn->dataDict->getNativeDeclaration($field['type'], $field_name, $field); - $query_fields[] = $query; + foreach ($fields as $fieldName => $field) { + $query = $this->getDeclaration($fieldName, $field); + + $queryFields[] = $query; } - return implode(', ', $query_fields); + return implode(', ', $queryFields); + } + /** + * Obtain DBMS specific SQL code portion needed to declare a generic type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @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. + * charset + * Text value with the default CHARACTER SET for this field. + * collation + * Text value with the default COLLATION for this field. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + */ + public function getDeclaration($name, $field) { + + $default = ''; + if(isset($field['default'])) { + if ($field['default'] === '') { + $field['default'] = empty($field['notnull']) + ? null : $this->valid_default_values[$field['type']]; + if ($field['default'] === '' + && ($db->options['portability'] & Doctrine::PORTABILITY_EMPTY_TO_NULL) + ) { + $field['default'] = ' '; + } + } + $default = ' DEFAULT ' . $this->conn->getDbh()->quote($field['default']); + } + /** + TODO: is this really needed for portability? + elseif(empty($field['notnull'])) { + $default = ' DEFAULT NULL'; + } + */ + + $charset = empty($field['charset']) ? '' : + ' '.$this->getCharsetFieldDeclaration($field['charset']); + + $collation = empty($field['collation']) ? '' : + ' '.$this->getCollationFieldDeclaration($field['collation']); + + $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; + + $name = $this->conn->quoteIdentifier($name, true); + + $method = 'get' . $field['type'] . 'Declaration'; + + if(method_exists($this->conn->dataDict, $method)) + return $this->conn->dataDict->$method($name, $field); + else + $dec = $this->conn->dataDict->getNativeDeclaration($field); + + return $name . ' ' . $dec . $charset . $default . $notnull . $collation; + } + /** + * 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 ''; + } + /** + * 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 ''; } /** * export diff --git a/lib/Doctrine/Hydrate.php b/lib/Doctrine/Hydrate.php index ffcece995..e8c4a83c1 100644 --- a/lib/Doctrine/Hydrate.php +++ b/lib/Doctrine/Hydrate.php @@ -92,10 +92,8 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { protected $pendingAggregates = array(); protected $aggregateMap = array(); - - protected $shortAliases = array(); - - protected $shortAliasIndexes = array(); + + protected $aliasHandler; /** * @var array $parts SQL query string parts */ @@ -120,6 +118,7 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { $connection = Doctrine_Manager::getInstance()->getCurrentConnection(); $this->connection = $connection; + $this->aliasHandler = new Doctrine_Hydrate_Alias(); } /** * getComponentAliases @@ -235,8 +234,7 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { $this->joins = array(); $this->tableIndexes = array(); $this->tableAliases = array(); - $this->shortAliases = array(); - $this->shortAliasIndexes = array(); + $this->aliasHandler->clear(); } /** * getConnection @@ -544,34 +542,14 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { return false; } public function getShortAliasIndex($alias) { - if( ! isset($this->shortAliasIndexes[$alias])) - return 0; - - return $this->shortAliasIndexes[$alias]; + return $this->aliasHandler->getShortAliasIndex($alias); } public function generateShortAlias($tableName) { - $char = strtolower(substr($tableName, 0, 1)); - - $alias = $char; - - if( ! isset($this->shortAliasIndexes[$alias])) - $this->shortAliasIndexes[$alias] = 1; - - while(isset($this->shortAliases[$alias])) { - $alias = $char . ++$this->shortAliasIndexes[$alias]; - } - $this->shortAliases[$alias] = $tableName; - - return $alias; + return $this->aliasHandler->generateShortAlias($tableName); } public function getShortAlias($tableName) { - $alias = array_search($tableName, $this->shortAliases); - - if($alias !== false) - return $alias; - - return $this->generateShortAlias($tableName); + return $this->aliasHandler->getShortAlias($tableName); } /** * applyInheritance diff --git a/lib/Doctrine/Manager.php b/lib/Doctrine/Manager.php index bdf23a34b..c4e321d28 100644 --- a/lib/Doctrine/Manager.php +++ b/lib/Doctrine/Manager.php @@ -98,8 +98,8 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera Doctrine::ATTR_AUTO_TYPE_VLD => true, Doctrine::ATTR_CREATE_TABLES => true, Doctrine::ATTR_QUERY_LIMIT => Doctrine::LIMIT_RECORDS, - Doctrine::ATTR_IDXNAME_FORMAT => '%_idx', - Doctrine::ATTR_SEQNAME_FORMAT => '%_seq', + Doctrine::ATTR_IDXNAME_FORMAT => "%s_idx", + Doctrine::ATTR_SEQNAME_FORMAT => "%s_seq", Doctrine::ATTR_QUOTE_IDENTIFIER => false, Doctrine::ATTR_SEQCOL_NAME => 'id', Doctrine::ATTR_PORTABILITY => Doctrine::PORTABILITY_ALL, diff --git a/lib/Doctrine/Query.php b/lib/Doctrine/Query.php index 3d3912109..0a9ae0000 100644 --- a/lib/Doctrine/Query.php +++ b/lib/Doctrine/Query.php @@ -343,8 +343,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $this->fetchModes = array(); $this->tableIndexes = array(); $this->tableAliases = array(); - $this->shortAliases = array(); - $this->shortAliasIndexes = array(); + $this->aliasHandler->clear(); $class = "Doctrine_Query_".ucwords($name); $parser = new $class($this); @@ -621,8 +620,8 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { if(strpos($part, "'") !== false) continue; - if(isset($this->shortAliases[$part])) { - $parts[$k] = $this->generateNewAlias($part); + if($this->aliasHandler->hasAliasFor($part)) { + $parts[$k] = $this->aliasHandler->generateNewAlias($part); } if(strpos($part, '.') !== false) { @@ -631,7 +630,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $trimmed = ltrim($e[0], '( '); $pos = strpos($e[0], $trimmed); - $e[0] = substr($e[0], 0, $pos) . $this->generateNewAlias($trimmed); + $e[0] = substr($e[0], 0, $pos) . $this->aliasHandler->generateNewAlias($trimmed); $parts[$k] = implode('.', $e); } } @@ -639,7 +638,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { return $subquery; } - + /** public function generateNewAlias($alias) { if(isset($this->shortAliases[$alias])) { // generate a new alias @@ -656,6 +655,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { return $alias; } + */