From 65ebec5aa932d7edc7e56dd2d117455b9274791e Mon Sep 17 00:00:00 2001 From: zYne Date: Thu, 11 Jan 2007 22:39:32 +0000 Subject: [PATCH] Fixed sqlite connection function binding issue when using Doctrine_Db as well as added proper primary key handling for export methods --- lib/Doctrine/Connection/Mssql.php | 58 ++++++++++++++++++++++++ lib/Doctrine/Connection/Sqlite.php | 2 +- lib/Doctrine/Export.php | 2 +- lib/Doctrine/Export/Mysql.php | 8 ++-- lib/Doctrine/Export/Sqlite.php | 56 +++++++++++++++++++++++ lib/Doctrine/Record.php | 17 ++++++- lib/Doctrine/Table.php | 71 +++++++++++++++++++++--------- 7 files changed, 185 insertions(+), 29 deletions(-) diff --git a/lib/Doctrine/Connection/Mssql.php b/lib/Doctrine/Connection/Mssql.php index bd2b83347..974447df8 100644 --- a/lib/Doctrine/Connection/Mssql.php +++ b/lib/Doctrine/Connection/Mssql.php @@ -138,4 +138,62 @@ class Doctrine_Connection_Mssql extends Doctrine_Connection return $query; } + /** + * return version information about the server + * + * @param bool $native determines if the raw version string should be returned + * @return mixed array/string with version information or MDB2 error object + * @access public + */ + function getServerVersion($native = false) + { + if ($this->connected_server_info) { + $serverInfo = $this->connected_server_info; + } else { + $query = 'SELECT @@VERSION'; + $serverInfo = $this->fetchOne($query); + } + // cache server_info + $this->connected_server_info = $serverInfo; + if ( ! $native) { + if (preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)/', $serverInfo, $tmp)) { + $serverInfo = array( + 'major' => $tmp[1], + 'minor' => $tmp[2], + 'patch' => $tmp[3], + 'extra' => null, + 'native' => $serverInfo, + ); + } else { + $serverInfo = array( + 'major' => null, + 'minor' => null, + 'patch' => null, + 'extra' => null, + 'native' => $serverInfo, + ); + } + } + return $serverInfo; + } + /** + * Checks if there's a sequence that exists. + * + * @param string $seq_name The sequence name to verify. + * @return boolean The value if the table exists or not + */ + public function checkSequence($seqName) + { + $query = 'SELECT * FROM ' . $seqName; + try { + $this->exec($query); + } catch(Doctrine_Connection_Exception $e) { + if ($e->getPortableCode() == Doctrine::ERR_NOSUCHTABLE) { + return false; + } + + throw $e; + } + return true; + } } diff --git a/lib/Doctrine/Connection/Sqlite.php b/lib/Doctrine/Connection/Sqlite.php index 331325b26..14813156b 100644 --- a/lib/Doctrine/Connection/Sqlite.php +++ b/lib/Doctrine/Connection/Sqlite.php @@ -74,7 +74,7 @@ class Doctrine_Connection_Sqlite extends Doctrine_Connection_Common $this->options['server_version'] = ''; */ parent::__construct($manager, $adapter); - $this->initFunctions(); + //$this->initFunctions(); } /** * initializes database functions missing in sqlite diff --git a/lib/Doctrine/Export.php b/lib/Doctrine/Export.php index 6562d9388..2f8a82923 100644 --- a/lib/Doctrine/Export.php +++ b/lib/Doctrine/Export.php @@ -144,7 +144,7 @@ class Doctrine_Export extends Doctrine_Connection_Module } $queryFields = $this->getFieldDeclarationList($fields); - if (!empty($options['primary'])) { + if (isset($options['primary']) && ! empty($options['primary'])) { $queryFields.= ', PRIMARY KEY('.implode(', ', array_values($options['primary'])).')'; } diff --git a/lib/Doctrine/Export/Mysql.php b/lib/Doctrine/Export/Mysql.php index 2a90893d1..f53ed46ea 100644 --- a/lib/Doctrine/Export/Mysql.php +++ b/lib/Doctrine/Export/Mysql.php @@ -101,7 +101,7 @@ class Doctrine_Export_Mysql extends Doctrine_Export } $query_fields = $this->getFieldDeclarationList($fields); - if ( ! empty($options['primary'])) { + if (isset($options['primary']) && ! empty($options['primary'])) { $query_fields.= ', PRIMARY KEY(' . implode(', ', array_values($options['primary'])) . ')'; } $name = $this->conn->quoteIdentifier($name, true); @@ -110,12 +110,12 @@ class Doctrine_Export_Mysql extends Doctrine_Export $optionStrings = array(); if (isset($options['comment'])) { - $optionStrings['comment'] = 'COMMENT = '.$this->dbh->quote($options['comment'], 'text'); + $optionStrings['comment'] = 'COMMENT = ' . $this->dbh->quote($options['comment'], 'text'); } if (isset($options['charset'])) { - $optionsSting['charset'] = 'DEFAULT CHARACTER SET '.$options['charset']; + $optionsSting['charset'] = 'DEFAULT CHARACTER SET ' . $options['charset']; if (isset($options['collate'])) { - $optionStrings['charset'].= ' COLLATE '.$options['collate']; + $optionStrings['charset'].= ' COLLATE ' . $options['collate']; } } diff --git a/lib/Doctrine/Export/Sqlite.php b/lib/Doctrine/Export/Sqlite.php index 75483650d..33714a605 100644 --- a/lib/Doctrine/Export/Sqlite.php +++ b/lib/Doctrine/Export/Sqlite.php @@ -89,6 +89,62 @@ class Doctrine_Export_Sqlite extends Doctrine_Export return $this->conn->exec($query); } + /** + * create a new table + * + * @param string $name Name of the database that should be created + * @param array $fields Associative array that contains the definition of each field of the new table + * The indexes of the array entries are the names of the fields of the table an + * the array entry values are associative arrays like those that are meant to be + * passed with the field definitions to get[Type]Declaration() functions. + * array( + * 'id' => array( + * 'type' => 'integer', + * 'unsigned' => 1 + * 'notnull' => 1 + * 'default' => 0 + * ), + * 'name' => array( + * 'type' => 'text', + * 'length' => 12 + * ), + * 'password' => array( + * 'type' => 'text', + * 'length' => 12 + * ) + * ); + * @param array $options An associative array of table options: + * + * @return void + */ + public function createTable($name, array $fields, array $options = array()) + { + if ( ! $name) { + throw new Doctrine_Export_Exception('no valid table name specified'); + } + + if (empty($fields)) { + throw new Doctrine_Export_Exception('no fields specified for table '.$name); + } + $queryFields = $this->getFieldDeclarationList($fields); + + $autoinc = false; + foreach($fields as $field) { + if(isset($field['autoincrement']) && $field['autoincrement']) { + $autoinc = true; + break; + } + } + + if ( ! $autoinc && isset($options['primary']) && ! empty($options['primary'])) { + $queryFields.= ', PRIMARY KEY('.implode(', ', array_values($options['primary'])).')'; + } + + $name = $this->conn->quoteIdentifier($name, true); + $query = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')'; + + return $this->conn->exec($query); + } /** * create sequence * diff --git a/lib/Doctrine/Record.php b/lib/Doctrine/Record.php index 67fdec26d..292e8980c 100644 --- a/lib/Doctrine/Record.php +++ b/lib/Doctrine/Record.php @@ -1445,10 +1445,25 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite { $this->_table->setEnumValues($column, $values); } + /** + * option + * sets or retrieves an option + * + * @see Doctrine_Table::$options availible options + * @param mixed $name + * @param mixed $value + * @return mixed + */ public function option($name, $value = null) { if ($value == null) { - $this->_table->getOption($name); + if (is_array($name)) { + foreach ($name as $k => $v) { + $this->_table->setOption($k, $v); + } + } else { + return $this->_table->getOption($name); + } } else { $this->_table->setOption($name, $value); } diff --git a/lib/Doctrine/Table.php b/lib/Doctrine/Table.php index 7a2d64784..b237f87fb 100644 --- a/lib/Doctrine/Table.php +++ b/lib/Doctrine/Table.php @@ -117,6 +117,10 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * * -- name name of the component, for example component name of the GroupTable is 'Group' * + * -- declaringClass name of the table definition declaring class (when using inheritance the class + * that defines the table structure can be any class in the inheritance hierarchy, + * hence we need reflection to check out which class actually calls setTableDefinition) + * * -- tableName database table name, in most cases this is the same as component name but in some cases * where one-table-multi-class inheritance is used this will be the name of the inherited table * @@ -183,6 +187,8 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $method = new ReflectionMethod($this->options['name'], 'setTableDefinition'); $class = $method->getDeclaringClass(); + $this->options['declaringClass'] = $class; + if ( ! isset($this->options['tableName'])) { $this->options['tableName'] = Doctrine::tableize($class->getName()); } @@ -247,28 +253,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable }; if ($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) { - if (Doctrine::isValidClassname($class->getName())) { - try { - $columns = array(); - foreach ($this->columns as $name => $column) { - $definition = $column[2]; - $definition['type'] = $column[0]; - $definition['length'] = $column[1]; - - if ($definition['type'] == 'enum' && isset($definition['default'])) { - $definition['default'] = $this->enumIndex($name, $definition['default']); - } - if ($definition['type'] == 'boolean' && isset($definition['default'])) { - $definition['default'] = (int) $definition['default']; - } - $columns[$name] = $definition; - } - - $this->conn->export->createTable($this->options['tableName'], $columns); - } catch(Exception $e) { - - } - } + $this->export(); } } @@ -290,6 +275,48 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable } $this->repository = new Doctrine_Table_Repository($this); } + /** + * export + * exports this table to database based on column and option definitions + * + * @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS + * occurred during the create table operation + * @return boolean whether or not the export operation was successful + * false if table already existed in the database + */ + public function export() { + if (Doctrine::isValidClassname($this->options['declaringClass']->getName())) { + try { + $columns = array(); + $primary = array(); + foreach ($this->columns as $name => $column) { + $definition = $column[2]; + $definition['type'] = $column[0]; + $definition['length'] = $column[1]; + + if ($definition['type'] == 'enum' && isset($definition['default'])) { + $definition['default'] = $this->enumIndex($name, $definition['default']); + } + if ($definition['type'] == 'boolean' && isset($definition['default'])) { + $definition['default'] = (int) $definition['default']; + } + $columns[$name] = $definition; + + if(isset($definition['primary']) && $definition['primary']) { + $primary[] = $name; + } + } + $options['primary'] = $primary; + + $this->conn->export->createTable($this->options['tableName'], $columns, array_merge($this->options, $options)); + } catch(Doctrine_Connection_Exception $e) { + // we only want to silence table already exists errors + if($e->getPortableCode !== Doctrine::ERR_ALREADY_EXISTS) { + throw $e; + } + } + } + } /** * createQuery * creates a new Doctrine_Query object and adds the component name