Merge branch '2.0-mssql' into 2.0

This commit is contained in:
Juan Basso 2011-05-24 00:07:56 -04:00
commit 2ea5be5de2
14 changed files with 373 additions and 467 deletions

View file

@ -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

View file

@ -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') {

View file

@ -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

View file

@ -1,6 +1,6 @@
<?php
/**
* MS SQL layer for DBO
* MS SQL Server layer for DBO
*
* PHP 5
*
@ -17,6 +17,8 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('DboSource', 'Model/Datasource');
/**
* MS SQL layer for DBO
*
@ -24,14 +26,14 @@
*
* @package cake.libs.model.datasources.dbo
*/
class DboMssql extends DboSource {
class Sqlserver extends DboSource {
/**
* Driver description
*
* @var string
*/
public $description = "MS SQL DBO Driver";
public $description = "SQL Server DBO Driver";
/**
* Starting quote character for quoted identifiers
@ -53,7 +55,14 @@ class DboMssql extends DboSource {
*
* @var array
*/
private $__fieldMappings = array();
protected $_fieldMappings = array();
/**
* Storing the last affected value
*
* @var mixed
*/
protected $_lastAffected = false;
/**
* Base configuration settings for MS SQL driver
@ -62,11 +71,10 @@ class DboMssql extends DboSource {
*/
protected $_baseConfig = array(
'persistent' => 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;
}
}
}

View file

@ -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;

View file

@ -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 '???'"
)
)
);

View file

@ -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);

View file

@ -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');

View file

@ -1,6 +1,6 @@
<?php
/**
* DboMssqlTest file
* SqlserverTest file
*
* PHP 5
*
@ -17,90 +17,57 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
require_once CAKE.'Model'.DS.'Model.php';
require_once CAKE.'Model'.DS.'Datasource'.DS.'DataSource.php';
require_once CAKE.'Model'.DS.'Datasource'.DS.'DboSource.php';
require_once CAKE.'Model'.DS.'Datasource'.DS.'Database'.DS.'Mssql.php';
App::uses('Model', 'Model');
App::uses('Sqlserver', 'Model/Datasource/Database');
/**
* DboMssqlTestDb class
* SqlserverTestDb class
*
* @package cake.tests.cases.libs.model.datasources.dbo
*/
class DboMssqlTestDb extends DboMssql {
class SqlserverTestDb extends Sqlserver {
/**
* simulated property
*
* @var array
* @access public
*/
public $simulated = array();
/**
* simalate property
* execute results stack
*
* @var array
* @access public
*/
public $simulate = true;
/**
* fetchAllResultsStack
*
* @var array
* @access public
*/
public $fetchAllResultsStack = array();
public $executeResultsStack = array();
/**
* execute method
*
* @param mixed $sql
* @access protected
* @return void
* @return mixed
*/
function _execute($sql) {
if ($this->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);
}
}

View file

@ -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();

View file

@ -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');

View file

@ -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'));

View file

@ -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,

View file

@ -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))
);
/**