diff --git a/app/Config/database.php.default b/app/Config/database.php.default index 81d3fa12c..234df8ea4 100644 --- a/app/Config/database.php.default +++ b/app/Config/database.php.default @@ -2,7 +2,7 @@ /** * This is core configuration file. * - * Use it to configure core behaviour ofCake. + * Use it to configure core behaviour of Cake. * * PHP 5 * @@ -31,7 +31,7 @@ * Database/Mysql - MySQL 4 & 5, * Database/Sqlite - SQLite (PHP5 only), * Database/Postgres - PostgreSQL 7 and higher, - * Database/Mssql - Microsoft SQL Server 2000 and higher, + * Database/Sqlserver - Microsoft SQL Server 2005 and higher, * Database/Oracle - Oracle 8 and higher * * You can add custom database drivers (or override existing drivers) by adding the diff --git a/lib/Cake/Console/Command/Task/DbConfigTask.php b/lib/Cake/Console/Command/Task/DbConfigTask.php index 7fb1064c8..e425f391f 100644 --- a/lib/Cake/Console/Command/Task/DbConfigTask.php +++ b/lib/Cake/Console/Command/Task/DbConfigTask.php @@ -104,7 +104,7 @@ class DbConfigTask extends Shell { } } - $driver = $this->in(__d('cake_console', 'Driver:'), array('Mssql', 'Mysql', 'Oracle', 'Postgres', 'Sqlite'), 'Mysql'); + $driver = $this->in(__d('cake_console', 'Driver:'), array('Mysql', 'Oracle', 'Postgres', 'Sqlite', 'Sqlserver'), 'Mysql'); $persistent = $this->in(__d('cake_console', 'Persistent Connection?'), array('y', 'n'), 'n'); if (strtolower($persistent) == 'n') { diff --git a/lib/Cake/Console/templates/skel/Config/database.php.default b/lib/Cake/Console/templates/skel/Config/database.php.default index 81d3fa12c..234df8ea4 100644 --- a/lib/Cake/Console/templates/skel/Config/database.php.default +++ b/lib/Cake/Console/templates/skel/Config/database.php.default @@ -2,7 +2,7 @@ /** * This is core configuration file. * - * Use it to configure core behaviour ofCake. + * Use it to configure core behaviour of Cake. * * PHP 5 * @@ -31,7 +31,7 @@ * Database/Mysql - MySQL 4 & 5, * Database/Sqlite - SQLite (PHP5 only), * Database/Postgres - PostgreSQL 7 and higher, - * Database/Mssql - Microsoft SQL Server 2000 and higher, + * Database/Sqlserver - Microsoft SQL Server 2005 and higher, * Database/Oracle - Oracle 8 and higher * * You can add custom database drivers (or override existing drivers) by adding the diff --git a/lib/Cake/Model/Datasource/Database/Mssql.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php similarity index 70% rename from lib/Cake/Model/Datasource/Database/Mssql.php rename to lib/Cake/Model/Datasource/Database/Sqlserver.php index b09e58a77..77a355853 100644 --- a/lib/Cake/Model/Datasource/Database/Mssql.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -1,6 +1,6 @@ true, - 'host' => 'localhost', - 'login' => 'root', + 'host' => '(local)\sqlexpress', + 'login' => '', 'password' => '', - 'database' => 'cake', - 'port' => '1433', + 'database' => 'cake' ); /** @@ -92,7 +100,6 @@ class DboMssql extends DboSource { * Index of basic SQL commands * * @var array - * @access protected */ protected $_commands = array( 'begin' => 'BEGIN TRANSACTION', @@ -104,92 +111,44 @@ class DboMssql extends DboSource { * Define if the last query had error * * @var string - * @access private */ private $__lastQueryHadError = false; -/** - * MS SQL DBO driver constructor; sets SQL Server error reporting defaults - * - * @param array $config Configuration data from app/config/databases.php - * @return boolean True if connected successfully, false on error - */ - function __construct($config, $autoConnect = true) { - if ($autoConnect) { - if (!function_exists('mssql_min_message_severity')) { - trigger_error(__d('cake_dev', "PHP SQL Server interface is not installed, cannot continue. For troubleshooting information, see http://php.net/mssql/"), E_USER_WARNING); - } - mssql_min_message_severity(15); - mssql_min_error_severity(2); - } - return parent::__construct($config, $autoConnect); - } /** * Connects to the database using options in the given configuration array. * * @return boolean True if the database could be connected, else false */ - function connect() { + public function connect() { $config = $this->config; - - $os = env('OS'); - if (!empty($os) && strpos($os, 'Windows') !== false) { - $sep = ','; - } else { - $sep = ':'; - } $this->connected = false; - - if (is_numeric($config['port'])) { - $port = $sep . $config['port']; // Port number - } elseif ($config['port'] === null) { - $port = ''; // No port - SQL Server 2005 - } else { - $port = '\\' . $config['port']; // Named pipe - } - - if (!$config['persistent']) { - $this->connection = mssql_connect($config['host'] . $port, $config['login'], $config['password'], true); - } else { - $this->connection = mssql_pconnect($config['host'] . $port, $config['login'], $config['password']); - } - - if (mssql_select_db($config['database'], $this->connection)) { - $this->_execute("SET DATEFORMAT ymd"); + try { + $flags = array(PDO::ATTR_PERSISTENT => $config['persistent']); + if (!empty($config['encoding'])) { + $flags[PDO::SQLSRV_ATTR_ENCODING] = $config['encoding']; + } + $this->_connection = new PDO( + "sqlsrv:server={$config['host']};Database={$config['database']}", + $config['login'], + $config['password'], + $flags + ); $this->connected = true; + } catch (PDOException $e) { + throw new MissingConnectionException(array('class' => $e->getMessage())); } + +// $this->_execute("SET DATEFORMAT ymd"); return $this->connected; } /** - * Check that MsSQL is installed/loaded + * Check that PDO SQL Server is installed/loaded * * @return boolean */ - function enabled() { - return extension_loaded('mssql'); - } -/** - * Disconnects from database. - * - * @return boolean True if the database could be disconnected, else false - */ - function disconnect() { - @mssql_free_result($this->results); - $this->connected = !@mssql_close($this->connection); - return !$this->connected; - } - -/** - * Executes given SQL statement. - * - * @param string $sql SQL statement - * @return resource Result resource identifier - */ - protected function _execute($sql) { - $result = @mssql_query($sql, $this->connection); - $this->__lastQueryHadError = ($result === false); - return $result; + public function enabled() { + return in_array('sqlsrv', PDO::getAvailableDrivers()); } /** @@ -197,23 +156,24 @@ class DboMssql extends DboSource { * * @return array Array of tablenames in the database */ - function listSources() { + public function listSources() { $cache = parent::listSources(); - - if ($cache != null) { + if ($cache !== null) { return $cache; } - $result = $this->fetchAll('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES', false); + $result = $this->_execute("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'"); - if (!$result || empty($result)) { + if (!$result) { + $result->closeCursor(); return array(); } else { $tables = array(); - foreach ($result as $table) { - $tables[] = $table[0]['TABLE_NAME']; + while ($line = $result->fetch()) { + $tables[] = $line[0]; } + $result->closeCursor(); parent::listSources($tables); return $tables; } @@ -225,42 +185,45 @@ class DboMssql extends DboSource { * @param Model $model Model object to describe * @return array Fields in table. Keys are name and type */ - function describe($model) { + public function describe($model) { $cache = parent::describe($model); - if ($cache != null) { return $cache; } - - $table = $this->fullTableName($model, false); - $cols = $this->fetchAll("SELECT COLUMN_NAME as Field, DATA_TYPE as Type, COL_LENGTH('" . $table . "', COLUMN_NAME) as Length, IS_NULLABLE As [Null], COLUMN_DEFAULT as [Default], COLUMNPROPERTY(OBJECT_ID('" . $table . "'), COLUMN_NAME, 'IsIdentity') as [Key], NUMERIC_SCALE as Size FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" . $table . "'", false); - $fields = false; + $table = $this->fullTableName($model, false); + $cols = $this->_execute("SELECT COLUMN_NAME as Field, DATA_TYPE as Type, COL_LENGTH('" . $table . "', COLUMN_NAME) as Length, IS_NULLABLE As [Null], COLUMN_DEFAULT as [Default], COLUMNPROPERTY(OBJECT_ID('" . $table . "'), COLUMN_NAME, 'IsIdentity') as [Key], NUMERIC_SCALE as Size FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" . $table . "'"); + if (!$cols) { + throw new CakeException(__d('cake_dev', 'Could not describe table for %s', $model->name)); + } + foreach ($cols as $column) { - $field = $column[0]['Field']; + $field = $column->Field; $fields[$field] = array( - 'type' => $this->column($column[0]['Type']), - 'null' => (strtoupper($column[0]['Null']) == 'YES'), - 'default' => preg_replace("/^[(]{1,2}'?([^')]*)?'?[)]{1,2}$/", "$1", $column[0]['Default']), - 'length' => intval($column[0]['Length']), - 'key' => ($column[0]['Key'] == '1') ? 'primary' : false + 'type' => $this->column($column->Type), + 'null' => ($column->Null === 'YES' ? true : false), + 'default' => preg_replace("/^[(]{1,2}'?([^')]*)?'?[)]{1,2}$/", "$1", $column->Default), + 'length' => intval($column->Length), + 'key' => ($column->Key == '1') ? 'primary' : false ); + if ($fields[$field]['default'] === 'null') { $fields[$field]['default'] = null; } else { $this->value($fields[$field]['default'], $fields[$field]['type']); } - if ($fields[$field]['key'] && $fields[$field]['type'] == 'integer') { + if ($fields[$field]['key'] !== false && $fields[$field]['type'] == 'integer') { $fields[$field]['length'] = 11; - } elseif (!$fields[$field]['key']) { + } elseif ($fields[$field]['key'] === false) { unset($fields[$field]['key']); } if (in_array($fields[$field]['type'], array('date', 'time', 'datetime', 'timestamp'))) { $fields[$field]['length'] = null; } } - $this->__cacheDescription($this->fullTableName($model, false), $fields); + $this->__cacheDescription($table, $fields); + $cols->closeCursor(); return $fields; } @@ -272,9 +235,15 @@ class DboMssql extends DboSource { * @param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided * @return string Quoted and escaped data */ - function value($data, $column = null, $safe = false) { + public function value($data, $column = null, $safe = false) { $parent = parent::value($data, $column, $safe); + if ($column === 'float' && strpos($data, '.') !== false) { + return rtrim($data, '0'); + } + if ($parent === "''" && ($column === null || $column !== 'string')) { + return 'NULL'; + } if ($parent != null) { return $parent; } @@ -315,7 +284,7 @@ class DboMssql extends DboSource { * @param mixed $fields * @return array */ - function fields($model, $alias = null, $fields = array(), $quote = true) { + public function fields($model, $alias = null, $fields = array(), $quote = true) { if (empty($alias)) { $alias = $model->alias; } @@ -331,7 +300,7 @@ class DboMssql extends DboSource { $prepend = 'DISTINCT '; $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i])); } - $fieldAlias = count($this->__fieldMappings); + $fieldAlias = count($this->_fieldMappings); if (!preg_match('/\s+AS\s+/i', $fields[$i])) { if (substr($fields[$i], -1) == '*') { @@ -348,12 +317,12 @@ class DboMssql extends DboSource { } if (strpos($fields[$i], '.') === false) { - $this->__fieldMappings[$alias . '__' . $fieldAlias] = $alias . '.' . $fields[$i]; + $this->_fieldMappings[$alias . '__' . $fieldAlias] = $alias . '.' . $fields[$i]; $fieldName = $this->name($alias . '.' . $fields[$i]); $fieldAlias = $this->name($alias . '__' . $fieldAlias); } else { $build = explode('.', $fields[$i]); - $this->__fieldMappings[$build[0] . '__' . $fieldAlias] = $fields[$i]; + $this->_fieldMappings[$build[0] . '__' . $fieldAlias] = $fields[$i]; $fieldName = $this->name($build[0] . '.' . $build[1]); $fieldAlias = $this->name(preg_replace("/^\[(.+)\]$/", "$1", $build[0]) . '__' . $fieldAlias); } @@ -381,7 +350,7 @@ class DboMssql extends DboSource { * @param mixed $conditions * @return array */ - function create($model, $fields = null, $values = null) { + public function create($model, $fields = null, $values = null) { if (!empty($values)) { $fields = array_combine($fields, $values); } @@ -411,7 +380,7 @@ class DboMssql extends DboSource { * @param mixed $conditions * @return array */ - function update($model, $fields = array(), $values = null, $conditions = null) { + public function update($model, $fields = array(), $values = null, $conditions = null) { if (!empty($values)) { $fields = array_combine($fields, $values); } @@ -424,58 +393,6 @@ class DboMssql extends DboSource { return parent::update($model, array_keys($fields), array_values($fields), $conditions); } -/** - * Returns a formatted error message from previous database operation. - * - * @return string Error message with error number - */ - function lastError() { - if ($this->__lastQueryHadError) { - $error = mssql_get_last_message(); - if ($error && !preg_match('/contexto de la base de datos a|contesto di database|changed database|contexte de la base de don|datenbankkontext/i', $error)) { - return $error; - } - } - return null; - } - -/** - * Returns number of affected rows in previous database operation. If no previous operation exists, - * this returns false. - * - * @return integer Number of affected rows - */ - function lastAffected() { - if ($this->_result) { - return mssql_rows_affected($this->connection); - } - return null; - } - -/** - * Returns number of rows in previous resultset. If no previous resultset exists, - * this returns false. - * - * @return integer Number of rows in resultset - */ - function lastNumRows() { - if ($this->_result) { - return @mssql_num_rows($this->_result); - } - return null; - } - -/** - * Returns the ID generated from the previous INSERT operation. - * - * @param unknown_type $source - * @return in - */ - function lastInsertId($source = null) { - $id = $this->fetchRow('SELECT SCOPE_IDENTITY() AS insertID', false); - return $id[0]['insertID']; - } - /** * Returns a limit statement in the correct format for the particular database. * @@ -483,7 +400,7 @@ class DboMssql extends DboSource { * @param integer $offset Offset from which to start results * @return string SQL limit/offset statement */ - function limit($limit, $offset = null) { + public function limit($limit, $offset = null) { if ($limit) { $rt = ''; if (!strpos(strtolower($limit), 'top') || strpos(strtolower($limit), 'top') === 0) { @@ -504,7 +421,7 @@ class DboMssql extends DboSource { * @param string $real Real database-layer column type (i.e. "varchar(255)") * @return string Abstract column type (i.e. "string") */ - function column($real) { + public function column($real) { if (is_array($real)) { $col = $real['name']; @@ -544,33 +461,32 @@ class DboMssql extends DboSource { } /** - * Enter description here... + * Builds a map of the columns contained in a result * - * @param unknown_type $results + * @param PDOStatement $results */ - function resultSet(&$results) { - $this->results =& $results; + public function resultSet($results) { $this->map = array(); - $numFields = mssql_num_fields($results); + $numFields = $results->columnCount(); $index = 0; - $j = 0; - while ($j < $numFields) { - $column = mssql_field_name($results, $j); + while ($numFields-- > 0) { + $column = $results->getColumnMeta($index); + $name = $column['name']; - if (strpos($column, '__')) { - if (isset($this->__fieldMappings[$column]) && strpos($this->__fieldMappings[$column], '.')) { - $map = explode('.', $this->__fieldMappings[$column]); - } elseif (isset($this->__fieldMappings[$column])) { - $map = array(0, $this->__fieldMappings[$column]); + if (strpos($name, '__')) { + if (isset($this->_fieldMappings[$name]) && strpos($this->_fieldMappings[$name], '.')) { + $map = explode('.', $this->_fieldMappings[$name]); + } elseif (isset($this->_fieldMappings[$name])) { + $map = array(0, $this->_fieldMappings[$name]); } else { - $map = array(0, $column); + $map = array(0, $name); } - $this->map[$index++] = $map; } else { - $this->map[$index++] = array(0, $column); + $map = array(0, $name); } - $j++; + $map[] = ($column['sqlsrv:decl_type'] == 'bit') ? 'boolean' : $column['native_type']; + $this->map[$index++] = $map; } } @@ -581,7 +497,7 @@ class DboMssql extends DboSource { * @param array $data Query data * @return string */ - function renderStatement($type, $data) { + public function renderStatement($type, $data) { switch (strtolower($type)) { case 'select': extract($data); @@ -631,9 +547,8 @@ class DboMssql extends DboSource { * * @param string $order * @return string - * @access private */ - function __switchSort($order) { + private function __switchSort($order) { $order = preg_replace('/\s+ASC/i', '__tmp_asc__', $order); $order = preg_replace('/\s+DESC/i', ' ASC', $order); return preg_replace('/__tmp_asc__/', ' DESC', $order); @@ -644,13 +559,12 @@ class DboMssql extends DboSource { * * @param string $sql A snippet of SQL representing an ORDER or WHERE statement * @return string The value of $sql with field names replaced - * @access private */ - function __mapFields($sql) { - if (empty($sql) || empty($this->__fieldMappings)) { + private function __mapFields($sql) { + if (empty($sql) || empty($this->_fieldMappings)) { return $sql; } - foreach ($this->__fieldMappings as $key => $val) { + foreach ($this->_fieldMappings as $key => $val) { $sql = preg_replace('/' . preg_quote($val) . '/', $this->name($key), $sql); $sql = preg_replace('/' . preg_quote($this->name($val)) . '/', $this->name($key), $sql); } @@ -665,31 +579,31 @@ class DboMssql extends DboSource { * @param boolean $cache Enables returning/storing cached query results * @return array Array of resultset rows, or false if no rows matched */ - function read($model, $queryData = array(), $recursive = null) { + public function read($model, $queryData = array(), $recursive = null) { $results = parent::read($model, $queryData, $recursive); - $this->__fieldMappings = array(); + $this->_fieldMappings = array(); return $results; } /** * Fetches the next row from the current result set * - * @return unknown + * @return mixed */ - function fetchResult() { - if ($row = mssql_fetch_row($this->results)) { + public function fetchResult() { + if ($row = $this->_result->fetch()) { $resultRow = array(); - $i = 0; - - foreach ($row as $index => $field) { - list($table, $column) = $this->map[$index]; - $resultRow[$table][$column] = $row[$index]; - $i++; + foreach ($this->map as $col => $meta) { + list($table, $column, $type) = $meta; + $resultRow[$table][$column] = $row[$col]; + if ($type === 'boolean' && !is_null($row[$col])) { + $resultRow[$table][$column] = $this->boolean($resultRow[$table][$column]); + } } return $resultRow; - } else { - return false; } + $this->_result->closeCursor(); + return false; } /** @@ -709,7 +623,16 @@ class DboMssql extends DboSource { if ($hasPrimaryKey) { $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' ON'); } - parent::insertMulti($table, $fields, $values); + + $table = $this->fullTableName($table); + $fields = implode(', ', array_map(array(&$this, 'name'), $fields)); + $this->begin(); + foreach ($values as $value) { + $holder = implode(', ', array_map(array(&$this, 'value'), $value)); + $this->_execute("INSERT INTO {$table} ({$fields}) VALUES ({$holder})"); + } + $this->commit(); + if ($hasPrimaryKey) { $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' OFF'); } @@ -722,10 +645,14 @@ class DboMssql extends DboSource { * where options can be 'default', 'length', or 'key'. * @return string */ - function buildColumn($column) { + public function buildColumn($column) { $result = preg_replace('/(int|integer)\([0-9]+\)/i', '$1', parent::buildColumn($column)); if (strpos($result, 'DEFAULT NULL') !== false) { - $result = str_replace('DEFAULT NULL', 'NULL', $result); + if (isset($column['default']) && $column['default'] === '') { + $result = str_replace('DEFAULT NULL', "DEFAULT ''", $result); + } else { + $result = str_replace('DEFAULT NULL', 'NULL', $result); + } } else if (array_keys($column) == array('type', 'name')) { $result .= ' NULL'; } @@ -739,7 +666,7 @@ class DboMssql extends DboSource { * @param string $table * @return string */ - function buildIndex($indexes, $table = null) { + public function buildIndex($indexes, $table = null) { $join = array(); foreach ($indexes as $name => $value) { @@ -763,17 +690,14 @@ class DboMssql extends DboSource { /** * Makes sure it will return the primary key * - * @param mixed $model - * @access protected + * @param mixed $model Model instance of table name * @return string */ - function _getPrimaryKey($model) { - if (is_object($model)) { - $schema = $model->schema(); - } else { - $schema = $this->describe($model); + protected function _getPrimaryKey($model) { + if (!is_object($model)) { + $model = new Model(false, $model); } - + $schema = $this->describe($model); foreach ($schema as $field => $props) { if (isset($props['key']) && $props['key'] == 'primary') { return $field; @@ -781,4 +705,49 @@ class DboMssql extends DboSource { } return null; } + +/** + * Returns number of affected rows in previous database operation. If no previous operation exists, + * this returns false. + * + * @return integer Number of affected rows + */ + public function lastAffected() { + $affected = parent::lastAffected(); + if ($affected === null && $this->_lastAffected !== false) { + return $this->_lastAffected; + } + return $affected; + } +/** + * Executes given SQL statement. + * + * @param string $sql SQL statement + * @param array $params list of params to be bound to query (supported only in select) + * @param array $prepareOptions Options to be used in the prepare statement + * @return mixed PDOStatement if query executes with no problem, true as the result of a succesfull, false on error + * query returning no rows, suchs as a CREATE statement, false otherwise + */ + protected function _execute($sql, $params = array(), $prepareOptions = array()) { + $this->_lastAffected = false; + if (strncasecmp($sql, 'SELECT', 6) == 0) { + $prepareOptions += array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL); + return parent::_execute($sql, $params, $prepareOptions); + } + try { + $this->_lastAffected = $this->_connection->exec($sql); + if ($this->_lastAffected === false) { + $this->_results = null; + $error = $this->_connection->errorInfo(); + $this->error = $error[2]; + return false; + } + return true; + } catch (PDOException $e) { + $this->_results = null; + $this->error = $e->getMessage(); + return false; + } + } + } diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index 8d3db098b..600b10625 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -450,10 +450,11 @@ class DboSource extends DataSource { * * @param string $sql SQL statement * @param array $params list of params to be bound to query - * @return PDOStatement if query executes with no problem, true as the result of a succesfull + * @param array $prepareOptions Options to be used in the prepare statement + * @return mixed PDOStatement if query executes with no problem, true as the result of a succesfull, false on error * query returning no rows, suchs as a CREATE statement, false otherwise */ - protected function _execute($sql, $params = array()) { + protected function _execute($sql, $params = array(), $prepareOptions = array()) { $sql = trim($sql); if (preg_match('/^(?:CREATE|ALTER|DROP)/i', $sql)) { $statements = array_filter(explode(';', $sql)); @@ -464,7 +465,7 @@ class DboSource extends DataSource { } try { - $query = $this->_connection->prepare($sql); + $query = $this->_connection->prepare($sql, $prepareOptions); $query->setFetchMode(PDO::FETCH_LAZY); if (!$query->execute($params)) { $this->_results = $query; diff --git a/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php index c423f979e..d6c24349c 100644 --- a/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php +++ b/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php @@ -3420,7 +3420,7 @@ class ContainableBehaviorTest extends CakeTestCase { 'foreignKey' => 'article_id', 'associationForeignKey' => 'tag_id', // LENGHT function mysql-only, using LIKE does almost the same - 'conditions' => 'ShortTag.tag LIKE "???"' + 'conditions' => "ShortTag.tag LIKE '???'" ) ) ); diff --git a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php index e7e46a8ed..19f79d8c1 100644 --- a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php +++ b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php @@ -431,8 +431,8 @@ class TranslateBehaviorTest extends CakeTestCase { $expected = array(1 => 'Titel #1', 2 => 'Titel #2', 3 => 'Titel #3'); $this->assertEqual($expected, $result); - // MSSQL trigger an error and stops the page even if the debug = 0 - if ($this->db instanceof Mssql) { + // SQL Server trigger an error and stops the page even if the debug = 0 + if ($this->db instanceof Sqlserver) { $debug = Configure::read('debug'); Configure::write('debug', 0); diff --git a/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php b/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php index 8643f6abc..bce2d2a73 100644 --- a/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php +++ b/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php @@ -606,6 +606,8 @@ class BehaviorCollectionTest extends CakeTestCase { * @return void */ function testBehaviorFindCallbacks() { + $this->skipIf($this->db instanceof Sqlserver, 'This test is not compatible with SQL Server.'); + $Apple = new Apple(); $expected = $Apple->find('all'); @@ -805,6 +807,8 @@ class BehaviorCollectionTest extends CakeTestCase { * @return void */ function testBehaviorBelongsToFindCallbacks() { + $this->skipIf($this->db instanceof Sqlserver, 'This test is not compatible with SQL Server.'); + $Apple = new Apple(); $Apple->unbindModel(array('hasMany' => array('Child'), 'hasOne' => array('Sample')), false); $expected = $Apple->find('all'); diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/MssqlTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php similarity index 61% rename from lib/Cake/Test/Case/Model/Datasource/Database/MssqlTest.php rename to lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php index 65c4c7e6a..7b4d7a7fa 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/MssqlTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php @@ -1,6 +1,6 @@ simulate) { - $this->simulated[] = $sql; - return null; - } else { - return parent::_execute($sql); - } + protected function _execute($sql) { + $this->simulated[] = $sql; + return empty($this->executeResultsStack) ? null : array_pop($this->executeResultsStack); } /** * fetchAll method * * @param mixed $sql - * @access protected * @return void */ - function _matchRecords($model, $conditions = null) { + protected function _matchRecords($model, $conditions = null) { return $this->conditions(array('id' => array(1, 2))); } -/** - * fetchAll method - * - * @param mixed $sql - * @access protected - * @return void - */ - function fetchAll($sql, $cache = true, $modelName = null) { - $result = parent::fetchAll($sql, $cache, $modelName); - if (!empty($this->fetchAllResultsStack)) { - return array_pop($this->fetchAllResultsStack); - } - return $result; - } - /** * getLastQuery method * - * @access public - * @return void + * @return string */ - function getLastQuery() { + public function getLastQuery() { return $this->simulated[count($this->simulated) - 1]; } @@ -108,43 +75,50 @@ class DboMssqlTestDb extends DboMssql { * getPrimaryKey method * * @param mixed $model - * @access public - * @return void + * @return string */ - function getPrimaryKey($model) { + public function getPrimaryKey($model) { return parent::_getPrimaryKey($model); } + /** * clearFieldMappings method * - * @access public * @return void */ - function clearFieldMappings() { - $this->__fieldMappings = array(); + public function clearFieldMappings() { + $this->_fieldMappings = array(); + } + +/** + * describe method + * + * @param object $model + * @return void + */ + public function describe($model) { + return empty($this->describe) ? parent::describe($model) : $this->describe; } } /** - * MssqlTestModel class + * SqlserverTestModel class * * @package cake.tests.cases.libs.model.datasources */ -class MssqlTestModel extends Model { +class SqlserverTestModel extends Model { /** * name property * - * @var string 'MssqlTestModel' - * @access public + * @var string 'SqlserverTestModel' */ - public $name = 'MssqlTestModel'; + public $name = 'SqlserverTestModel'; /** * useTable property * * @var bool false - * @access public */ public $useTable = false; @@ -152,7 +126,6 @@ class MssqlTestModel extends Model { * _schema property * * @var array - * @access protected */ protected $_schema = array( 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8', 'key' => 'primary'), @@ -179,10 +152,9 @@ class MssqlTestModel extends Model { * belongsTo property * * @var array - * @access public */ public $belongsTo = array( - 'MssqlClientTestModel' => array( + 'SqlserverClientTestModel' => array( 'foreignKey' => 'client_id' ) ); @@ -193,10 +165,9 @@ class MssqlTestModel extends Model { * @param mixed $fields * @param mixed $order * @param mixed $recursive - * @access public * @return void */ - function find($conditions = null, $fields = null, $order = null, $recursive = null) { + public function find($conditions = null, $fields = null, $order = null, $recursive = null) { return $conditions; } @@ -207,50 +178,37 @@ class MssqlTestModel extends Model { * @param mixed $fields * @param mixed $order * @param mixed $recursive - * @access public - * @return void + * @return array */ - function findAll($conditions = null, $fields = null, $order = null, $recursive = null) { + public function findAll($conditions = null, $fields = null, $order = null, $recursive = null) { return $conditions; } - -/** - * setSchema method - * - * @param array $schema - * @access public - * @return void - */ - function setSchema($schema) { - $this->_schema = $schema; - } } /** - * MssqlClientTestModel class + * SqlserverClientTestModel class * * @package cake.tests.cases.libs.model.datasources */ -class MssqlClientTestModel extends Model { +class SqlserverClientTestModel extends Model { /** * name property * - * @var string 'MssqlAssociatedTestModel' - * @access public + * @var string 'SqlserverAssociatedTestModel' */ - public $name = 'MssqlClientTestModel'; + public $name = 'SqlserverClientTestModel'; + /** * useTable property * * @var bool false - * @access public */ public $useTable = false; + /** * _schema property * * @var array - * @access protected */ protected $_schema = array( 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8', 'key' => 'primary'), @@ -260,18 +218,32 @@ class MssqlClientTestModel extends Model { 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null) ); } + /** - * DboMssqlTest class + * SqlserverTestResultIterator class + * + * @package cake.tests.cases.libs.model.datasources + */ +class SqlserverTestResultIterator extends ArrayIterator { +/** + * closeCursor method + * + * @return void + */ + public function closeCursor() {} +} + +/** + * SqlserverTest class * * @package cake.tests.cases.libs.model.datasources.dbo */ -class DboMssqlTest extends CakeTestCase { +class SqlserverTest extends CakeTestCase { /** * The Dbo instance to be tested * * @var DboSource - * @access public */ public $db = null; @@ -279,70 +251,46 @@ class DboMssqlTest extends CakeTestCase { * autoFixtures property * * @var bool false - * @access public */ public $autoFixtures = false; + /** * fixtures property * * @var array - * @access public */ public $fixtures = array('core.category'); -/** - * Skip if cannot connect to mssql - * - */ - public function skip() { - $this->_initDb(); - $this->skipUnless($this->db->config['driver'] == 'mssql', '%s SQL Server connection not available'); - } -/** - * Make sure all fixtures tables are being created - * - */ - public function start() { - $this->db->simulate = false; - parent::start(); - $this->db->simulate = true; - } -/** - * Make sure all fixtures tables are being dropped - * - */ - public function end() { - $this->db->simulate = false; - parent::end(); - $this->db->simulate = true; - } /** * Sets up a Dbo class instance for testing * */ public function setUp() { - $db = ConnectionManager::getDataSource('test'); - $this->db = new DboMssqlTestDb($db->config); - $this->model = new MssqlTestModel(); + $this->Dbo = ConnectionManager::getDataSource('test'); + if (!($this->Dbo instanceof Sqlserver)) { + $this->markTestSkipped('Please configure the test datasource to use SQL Server.'); + } + $this->db = new SqlserverTestDb($this->Dbo->config); + $this->model = new SqlserverTestModel(); } /** * tearDown method * - * @access public * @return void */ - function tearDown() { + public function tearDown() { + unset($this->Dbo); + unset($this->db); unset($this->model); } /** * testQuoting method * - * @access public * @return void */ - function testQuoting() { + public function testQuoting() { $expected = "1.2"; $result = $this->db->value(1.2, 'float'); $this->assertIdentical($expected, $result); @@ -366,29 +314,28 @@ class DboMssqlTest extends CakeTestCase { /** * testFields method * - * @access public * @return void */ - function testFields() { + public function testFields() { $fields = array( - '[MssqlTestModel].[id] AS [MssqlTestModel__0]', - '[MssqlTestModel].[client_id] AS [MssqlTestModel__1]', - '[MssqlTestModel].[name] AS [MssqlTestModel__2]', - '[MssqlTestModel].[login] AS [MssqlTestModel__3]', - '[MssqlTestModel].[passwd] AS [MssqlTestModel__4]', - '[MssqlTestModel].[addr_1] AS [MssqlTestModel__5]', - '[MssqlTestModel].[addr_2] AS [MssqlTestModel__6]', - '[MssqlTestModel].[zip_code] AS [MssqlTestModel__7]', - '[MssqlTestModel].[city] AS [MssqlTestModel__8]', - '[MssqlTestModel].[country] AS [MssqlTestModel__9]', - '[MssqlTestModel].[phone] AS [MssqlTestModel__10]', - '[MssqlTestModel].[fax] AS [MssqlTestModel__11]', - '[MssqlTestModel].[url] AS [MssqlTestModel__12]', - '[MssqlTestModel].[email] AS [MssqlTestModel__13]', - '[MssqlTestModel].[comments] AS [MssqlTestModel__14]', - 'CONVERT(VARCHAR(20), [MssqlTestModel].[last_login], 20) AS [MssqlTestModel__15]', - '[MssqlTestModel].[created] AS [MssqlTestModel__16]', - 'CONVERT(VARCHAR(20), [MssqlTestModel].[updated], 20) AS [MssqlTestModel__17]' + '[SqlserverTestModel].[id] AS [SqlserverTestModel__0]', + '[SqlserverTestModel].[client_id] AS [SqlserverTestModel__1]', + '[SqlserverTestModel].[name] AS [SqlserverTestModel__2]', + '[SqlserverTestModel].[login] AS [SqlserverTestModel__3]', + '[SqlserverTestModel].[passwd] AS [SqlserverTestModel__4]', + '[SqlserverTestModel].[addr_1] AS [SqlserverTestModel__5]', + '[SqlserverTestModel].[addr_2] AS [SqlserverTestModel__6]', + '[SqlserverTestModel].[zip_code] AS [SqlserverTestModel__7]', + '[SqlserverTestModel].[city] AS [SqlserverTestModel__8]', + '[SqlserverTestModel].[country] AS [SqlserverTestModel__9]', + '[SqlserverTestModel].[phone] AS [SqlserverTestModel__10]', + '[SqlserverTestModel].[fax] AS [SqlserverTestModel__11]', + '[SqlserverTestModel].[url] AS [SqlserverTestModel__12]', + '[SqlserverTestModel].[email] AS [SqlserverTestModel__13]', + '[SqlserverTestModel].[comments] AS [SqlserverTestModel__14]', + 'CONVERT(VARCHAR(20), [SqlserverTestModel].[last_login], 20) AS [SqlserverTestModel__15]', + '[SqlserverTestModel].[created] AS [SqlserverTestModel__16]', + 'CONVERT(VARCHAR(20), [SqlserverTestModel].[updated], 20) AS [SqlserverTestModel__17]' ); $result = $this->db->fields($this->model); @@ -396,7 +343,7 @@ class DboMssqlTest extends CakeTestCase { $this->assertEqual($expected, $result); $this->db->clearFieldMappings(); - $result = $this->db->fields($this->model, null, 'MssqlTestModel.*'); + $result = $this->db->fields($this->model, null, 'SqlserverTestModel.*'); $expected = $fields; $this->assertEqual($expected, $result); @@ -408,23 +355,22 @@ class DboMssqlTest extends CakeTestCase { $this->assertEqual($expected, $result); $this->db->clearFieldMappings(); - $result = $this->db->fields($this->model, null, array('*', 'MssqlClientTestModel.*')); + $result = $this->db->fields($this->model, null, array('*', 'SqlserverClientTestModel.*')); $expected = array_merge($fields, array( - '[MssqlClientTestModel].[id] AS [MssqlClientTestModel__18]', - '[MssqlClientTestModel].[name] AS [MssqlClientTestModel__19]', - '[MssqlClientTestModel].[email] AS [MssqlClientTestModel__20]', - 'CONVERT(VARCHAR(20), [MssqlClientTestModel].[created], 20) AS [MssqlClientTestModel__21]', - 'CONVERT(VARCHAR(20), [MssqlClientTestModel].[updated], 20) AS [MssqlClientTestModel__22]')); + '[SqlserverClientTestModel].[id] AS [SqlserverClientTestModel__18]', + '[SqlserverClientTestModel].[name] AS [SqlserverClientTestModel__19]', + '[SqlserverClientTestModel].[email] AS [SqlserverClientTestModel__20]', + 'CONVERT(VARCHAR(20), [SqlserverClientTestModel].[created], 20) AS [SqlserverClientTestModel__21]', + 'CONVERT(VARCHAR(20), [SqlserverClientTestModel].[updated], 20) AS [SqlserverClientTestModel__22]')); $this->assertEqual($expected, $result); } /** * testDistinctFields method * - * @access public * @return void */ - function testDistinctFields() { + public function testDistinctFields() { $result = $this->db->fields($this->model, null, array('DISTINCT Car.country_code')); $expected = array('DISTINCT [Car].[country_code] AS [Car__0]'); $this->assertEqual($expected, $result); @@ -437,12 +383,11 @@ class DboMssqlTest extends CakeTestCase { /** * testDistinctWithLimit method * - * @access public * @return void */ - function testDistinctWithLimit() { + public function testDistinctWithLimit() { $this->db->read($this->model, array( - 'fields' => array('DISTINCT MssqlTestModel.city', 'MssqlTestModel.country'), + 'fields' => array('DISTINCT SqlserverTestModel.city', 'SqlserverTestModel.country'), 'limit' => 5 )); $result = $this->db->getLastQuery(); @@ -452,23 +397,20 @@ class DboMssqlTest extends CakeTestCase { /** * testDescribe method * - * @access public * @return void */ - function testDescribe() { - $MssqlTableDescription = array( - 0 => array( - 0 => array( - 'Default' => '((0))', - 'Field' => 'count', - 'Key' => 0, - 'Length' => '4', - 'Null' => 'NO', - 'Type' => 'integer', - ) + public function testDescribe() { + $SqlserverTableDescription = new SqlserverTestResultIterator(array( + (object) array( + 'Default' => '((0))', + 'Field' => 'count', + 'Key' => 0, + 'Length' => '4', + 'Null' => 'NO', + 'Type' => 'integer' ) - ); - $this->db->fetchAllResultsStack = array($MssqlTableDescription); + )); + $this->db->executeResultsStack = array($SqlserverTableDescription); $dummyModel = $this->model; $result = $this->db->describe($dummyModel); $expected = array( @@ -484,15 +426,15 @@ class DboMssqlTest extends CakeTestCase { /** * testBuildColumn * - * @return unknown_type + * @return void */ public function testBuildColumn() { - $column = array('name' => 'id', 'type' => 'integer', 'null' => '', 'default' => '', 'length' => '8', 'key' => 'primary'); + $column = array('name' => 'id', 'type' => 'integer', 'null' => false, 'default' => '', 'length' => '8', 'key' => 'primary'); $result = $this->db->buildColumn($column); $expected = '[id] int IDENTITY (1, 1) NOT NULL'; $this->assertEqual($expected, $result); - $column = array('name' => 'client_id', 'type' => 'integer', 'null' => '', 'default' => '0', 'length' => '11'); + $column = array('name' => 'client_id', 'type' => 'integer', 'null' => false, 'default' => '0', 'length' => '11'); $result = $this->db->buildColumn($column); $expected = '[client_id] int DEFAULT 0 NOT NULL'; $this->assertEqual($expected, $result); @@ -513,7 +455,7 @@ class DboMssqlTest extends CakeTestCase { $expected = '[name] varchar(255) NULL'; $this->assertEqual($expected, $result); - $column = array('name' => 'name', 'type' => 'string', 'null' => '', 'default' => '', 'length' => '255'); + $column = array('name' => 'name', 'type' => 'string', 'null' => false, 'default' => '', 'length' => '255'); $result = $this->db->buildColumn($column); $expected = '[name] varchar(255) DEFAULT \'\' NOT NULL'; $this->assertEqual($expected, $result); @@ -570,13 +512,13 @@ class DboMssqlTest extends CakeTestCase { * @return void */ public function testUpdateAllSyntax() { - $fields = array('MssqlTestModel.client_id' => '[MssqlTestModel].[client_id] + 1'); - $conditions = array('MssqlTestModel.updated <' => date('2009-01-01 00:00:00')); + $fields = array('SqlserverTestModel.client_id' => '[SqlserverTestModel].[client_id] + 1'); + $conditions = array('SqlserverTestModel.updated <' => date('2009-01-01 00:00:00')); $this->db->update($this->model, $fields, null, $conditions); $result = $this->db->getLastQuery(); - $this->assertNoPattern('/MssqlTestModel/', $result); - $this->assertPattern('/^UPDATE \[mssql_test_models\]/', $result); + $this->assertNoPattern('/SqlserverTestModel/', $result); + $this->assertPattern('/^UPDATE \[sqlserver_test_models\]/', $result); $this->assertPattern('/SET \[client_id\] = \[client_id\] \+ 1/', $result); } @@ -586,21 +528,16 @@ class DboMssqlTest extends CakeTestCase { * @return void */ public function testGetPrimaryKey() { - // When param is a model + $schema = $this->model->schema(); + + $this->db->describe = $schema; $result = $this->db->getPrimaryKey($this->model); $this->assertEqual($result, 'id'); - - $schema = $this->model->schema(); + unset($schema['id']['key']); - $this->model->setSchema($schema); + $this->db->describe = $schema; $result = $this->db->getPrimaryKey($this->model); $this->assertNull($result); - - // When param is a table name - $this->db->simulate = false; - $this->loadFixtures('Category'); - $result = $this->db->getPrimaryKey('categories'); - $this->assertEqual($result, 'id'); } /** @@ -609,52 +546,34 @@ class DboMssqlTest extends CakeTestCase { * @return void */ public function testInsertMulti() { + $this->db->describe = $this->model->schema(); + $fields = array('id', 'name', 'login'); - $values = array('(1, \'Larry\', \'PhpNut\')', '(2, \'Renan\', \'renan.saddam\')'); + $values = array( + array(1, 'Larry', 'PhpNut'), + array(2, 'Renan', 'renan.saddam')); $this->db->simulated = array(); $this->db->insertMulti($this->model, $fields, $values); $result = $this->db->simulated; $expected = array( - 'SET IDENTITY_INSERT [mssql_test_models] ON', - 'INSERT INTO [mssql_test_models] ([id], [name], [login]) VALUES (1, \'Larry\', \'PhpNut\')', - 'INSERT INTO [mssql_test_models] ([id], [name], [login]) VALUES (2, \'Renan\', \'renan.saddam\')', - 'SET IDENTITY_INSERT [mssql_test_models] OFF' + 'SET IDENTITY_INSERT [sqlserver_test_models] ON', + "INSERT INTO [sqlserver_test_models] ([id], [name], [login]) VALUES (1, 'Larry', 'PhpNut')", + "INSERT INTO [sqlserver_test_models] ([id], [name], [login]) VALUES (2, 'Renan', 'renan.saddam')", + 'SET IDENTITY_INSERT [sqlserver_test_models] OFF' ); $this->assertEqual($expected, $result); $fields = array('name', 'login'); - $values = array('(\'Larry\', \'PhpNut\')', '(\'Renan\', \'renan.saddam\')'); + $values = array( + array('Larry', 'PhpNut'), + array('Renan', 'renan.saddam')); $this->db->simulated = array(); $this->db->insertMulti($this->model, $fields, $values); $result = $this->db->simulated; $expected = array( - 'INSERT INTO [mssql_test_models] ([name], [login]) VALUES (\'Larry\', \'PhpNut\')', - 'INSERT INTO [mssql_test_models] ([name], [login]) VALUES (\'Renan\', \'renan.saddam\')' + "INSERT INTO [sqlserver_test_models] ([name], [login]) VALUES ('Larry', 'PhpNut')", + "INSERT INTO [sqlserver_test_models] ([name], [login]) VALUES ('Renan', 'renan.saddam')", ); $this->assertEqual($expected, $result); } -/** - * testLastError - * - * @return void - */ - public function testLastError() { - $debug = Configure::read('debug'); - Configure::write('debug', 0); - - $this->db->simulate = false; - $query = 'SELECT [name] FROM [categories]'; - $this->assertTrue($this->db->execute($query) !== false); - $this->assertNull($this->db->lastError()); - - $query = 'SELECT [inexistent_field] FROM [categories]'; - $this->assertFalse($this->db->execute($query)); - $this->assertNotNull($this->db->lastError()); - - $query = 'SELECT [name] FROM [categories]'; - $this->assertTrue($this->db->execute($query) !== false); - $this->assertNull($this->db->lastError()); - - Configure::write('debug', $debug); - } } diff --git a/lib/Cake/Test/Case/Model/ModelIntegrationTest.php b/lib/Cake/Test/Case/Model/ModelIntegrationTest.php index 1b4d68024..e9d4c66fa 100644 --- a/lib/Cake/Test/Case/Model/ModelIntegrationTest.php +++ b/lib/Cake/Test/Case/Model/ModelIntegrationTest.php @@ -634,6 +634,8 @@ class ModelIntegrationTest extends BaseModelTest { * @return void */ function testDeconstructFieldsTime() { + $this->skipIf($this->db instanceof Sqlserver, 'This test is not compatible with SQL Server.'); + $this->loadFixtures('Apple'); $TestModel = new Apple(); @@ -721,6 +723,8 @@ class ModelIntegrationTest extends BaseModelTest { * @return void */ function testDeconstructFieldsDateTime() { + $this->skipIf($this->db instanceof Sqlserver, 'This test is not compatible with SQL Server.'); + $this->loadFixtures('Apple'); $TestModel = new Apple(); diff --git a/lib/Cake/Test/Case/Model/ModelReadTest.php b/lib/Cake/Test/Case/Model/ModelReadTest.php index 84a4ea913..f0518e83a 100644 --- a/lib/Cake/Test/Case/Model/ModelReadTest.php +++ b/lib/Cake/Test/Case/Model/ModelReadTest.php @@ -79,8 +79,8 @@ class ModelReadTest extends BaseModelTest { */ function testGroupBy() { $db = ConnectionManager::getDataSource('test'); - $isStrictGroupBy = $this->db instanceof Postgres || $this->db instanceof Sqlite || $this->db instanceof Oracle; - $message = 'Postgres and Oracle have strict GROUP BY and are incompatible with this test.'; + $isStrictGroupBy = $this->db instanceof Postgres || $this->db instanceof Sqlite || $this->db instanceof Oracle || $this->db instanceof Sqlserver; + $message = 'Postgres, Oracle, SQLite and SQL Server have strict GROUP BY and are incompatible with this test.'; if ($this->skipIf($isStrictGroupBy, $message )) { return; @@ -367,13 +367,6 @@ class ModelReadTest extends BaseModelTest { * @return void */ function testVeryStrangeUseCase() { - $message = "skipping SELECT * FROM ? WHERE ? = ? AND ? = ?; prepared query."; - $message .= " MSSQL is incompatible with this test."; - - if ($this->skipIf($this->db instanceof Mssql, $message)) { - return; - } - $this->loadFixtures('Article', 'User', 'Tag', 'ArticlesTag'); $Article = new Article(); @@ -397,6 +390,10 @@ class ModelReadTest extends BaseModelTest { * @return void */ function testRecursiveUnbind() { + if ($this->skipIf($this->db instanceof Sqlserver, 'The test of testRecursiveUnbind test is not compatible with SQL Server, because it check for time columns.')) { + return; + } + $this->loadFixtures('Apple', 'Sample'); $TestModel = new Apple(); $TestModel->recursive = 2; @@ -2992,7 +2989,7 @@ class ModelReadTest extends BaseModelTest { * @return void */ function testSelfAssociationAfterFind() { - $this->loadFixtures('Apple'); + $this->loadFixtures('Apple', 'Sample'); $afterFindModel = new NodeAfterFind(); $afterFindModel->recursive = 3; $afterFindData = $afterFindModel->find('all'); @@ -3651,6 +3648,10 @@ class ModelReadTest extends BaseModelTest { * @return void */ function testFindCombinedRelations() { + if ($this->skipIf($this->db instanceof Sqlserver, 'The test of testRecursiveUnbind test is not compatible with SQL Server, because it check for time columns.')) { + return; + } + $this->loadFixtures('Apple', 'Sample'); $TestModel = new Apple(); @@ -3947,7 +3948,7 @@ class ModelReadTest extends BaseModelTest { $TestModel = new Basket(); $recursive = 3; - $result = $TestModel->find('all', compact('conditions', 'recursive')); + $result = $TestModel->find('all', compact('recursive')); $expected = array( array( @@ -6227,7 +6228,7 @@ class ModelReadTest extends BaseModelTest { // These tests are expected to fail on SQL Server since the LIMIT/OFFSET // hack can't handle small record counts. - if ($this->db instanceof Mssql) { + if (!($this->db instanceof Sqlserver)) { $result = $TestModel->find('all', array('limit' => 3, 'page' => 2)); $expected = array( array( @@ -6621,13 +6622,9 @@ class ModelReadTest extends BaseModelTest { * @return void */ function testFindCountDistinct() { - $skip = $this->skipIf( - $this->db instanceof Sqlite, - 'SELECT COUNT(DISTINCT field) is not compatible with SQLite' - ); - if ($skip) { - return; - } + $this->skipIf($this->db instanceof Sqlite, 'SELECT COUNT(DISTINCT field) is not compatible with SQLite'); + $this->skipIf($this->db instanceof Sqlserver, 'This test is not compatible with SQL Server.'); + $this->loadFixtures('Project'); $TestModel = new Project(); $TestModel->create(array('name' => 'project')) && $TestModel->save(); @@ -7398,10 +7395,13 @@ class ModelReadTest extends BaseModelTest { $result = $Post->find('first'); $this->assertEqual($result['Post']['two'], 2); - $Post->Author->virtualFields = array('false' => '1 = 2'); - $result = $Post->find('first'); - $this->assertEqual($result['Post']['two'], 2); - $this->assertFalse((bool)$result['Author']['false']); + // SQL Server does not support operators in expressions + if (!($this->db instanceof Sqlserver)) { + $Post->Author->virtualFields = array('false' => '1 = 2'); + $result = $Post->find('first'); + $this->assertEqual($result['Post']['two'], 2); + $this->assertFalse((bool)$result['Author']['false']); + } $result = $Post->find('first',array('fields' => array('author_id'))); $this->assertFalse(isset($result['Post']['two'])); @@ -7470,7 +7470,7 @@ class ModelReadTest extends BaseModelTest { * */ public function testVirtualFieldsMysql() { - if ($this->skipIf(!($this->db instanceof Mysql), 'The rest of virtualFieds test is not compatible with Postgres')) { + if ($this->skipIf(!($this->db instanceof Mysql), 'The rest of virtualFieds test only compatible with Mysql')) { return; } $this->loadFixtures('Post', 'Author'); diff --git a/lib/Cake/Test/Case/Model/ModelWriteTest.php b/lib/Cake/Test/Case/Model/ModelWriteTest.php index 15224e6ad..b42ba2bd2 100644 --- a/lib/Cake/Test/Case/Model/ModelWriteTest.php +++ b/lib/Cake/Test/Case/Model/ModelWriteTest.php @@ -415,7 +415,12 @@ class ModelWriteTest extends BaseModelTest { } $this->loadFixtures('CategoryThread'); - $this->db->query('ALTER TABLE '. $this->db->fullTableName('category_threads') . " ADD COLUMN child_count INTEGER"); + $column = 'COLUMN '; + if ($this->db instanceof Sqlserver) { + $column = ''; + } + $column .= $this->db->buildColumn(array('name' => 'child_count', 'type' => 'integer')); + $this->db->query('ALTER TABLE '. $this->db->fullTableName('category_threads') . ' ADD ' . $column); $Category = new CategoryThread(); $result = $Category->updateAll(array('CategoryThread.name' => "'updated'"), array('CategoryThread.parent_id' => 5)); $this->assertFalse(empty($result)); @@ -424,7 +429,7 @@ class ModelWriteTest extends BaseModelTest { $Category->belongsTo['ParentCategory']['counterCache'] = 'child_count'; $Category->updateCounterCache(array('parent_id' => 5)); $result = Set::extract($Category->find('all', array('conditions' => array('CategoryThread.id' => 5))), '{n}.CategoryThread.child_count'); - $expected = array_fill(0, 1, 1); + $expected = array(1); $this->assertEqual($expected, $result); } @@ -3829,6 +3834,8 @@ class ModelWriteTest extends BaseModelTest { * @return void */ function testUpdateAllEmptyValues() { + $this->skipIf($this->db instanceof Sqlserver, 'This test is not compatible with SQL Server.'); + $this->loadFixtures('Author', 'Post'); $model = new Author(); $result = $model->updateAll(array('user' => '""')); @@ -3948,6 +3955,8 @@ class ModelWriteTest extends BaseModelTest { * @return void */ function testSaveAllEmptyData() { + $this->skipIf($this->db instanceof Sqlserver, 'This test is not compatible with SQL Server.'); + $this->loadFixtures('Article', 'ProductUpdateAll', 'Comment', 'Attachment'); $model = new Article(); $result = $model->saveAll(array(), array('validate' => 'first')); diff --git a/lib/Cake/Test/Case/Network/CakeRequestTest.php b/lib/Cake/Test/Case/Network/CakeRequestTest.php index 25c9c8ab2..589dee1f6 100644 --- a/lib/Cake/Test/Case/Network/CakeRequestTest.php +++ b/lib/Cake/Test/Case/Network/CakeRequestTest.php @@ -172,7 +172,7 @@ class CakeRequestTestCase extends CakeTestCase { function testFILESParsing() { $_FILES = array('data' => array('name' => array( 'File' => array( - array('data' => 'cake_mssql_patch.patch'), + array('data' => 'cake_sqlserver_patch.patch'), array('data' => 'controller.diff'), array('data' => ''), array('data' => ''), @@ -221,7 +221,7 @@ class CakeRequestTestCase extends CakeTestCase { $expected = array( 'File' => array( array('data' => array( - 'name' => 'cake_mssql_patch.patch', + 'name' => 'cake_sqlserver_patch.patch', 'type' => '', 'tmp_name' => '/private/var/tmp/phpy05Ywj', 'error' => 0, diff --git a/lib/Cake/Test/Fixture/ArticlesTagFixture.php b/lib/Cake/Test/Fixture/ArticlesTagFixture.php index c475d87a4..c394f6ca9 100644 --- a/lib/Cake/Test/Fixture/ArticlesTagFixture.php +++ b/lib/Cake/Test/Fixture/ArticlesTagFixture.php @@ -41,7 +41,7 @@ class ArticlesTagFixture extends CakeTestFixture { public $fields = array( 'article_id' => array('type' => 'integer', 'null' => false), 'tag_id' => array('type' => 'integer', 'null' => false), - 'indexes' => array('UNIQUE_TAG' => array('column'=> array('article_id', 'tag_id'), 'unique'=>1)) + 'indexes' => array('UNIQUE_TAG2' => array('column'=> array('article_id', 'tag_id'), 'unique'=>1)) ); /**