Trying to fix the Mssql as much as possible.

Adding  parameter to the insertMulti() method because Mssql tries to get the table schema and it fails most of the time.
This commit is contained in:
Renan Gonçalves 2011-05-18 20:12:36 +02:00
parent d1a984cde9
commit 37b9bd59bc
6 changed files with 102 additions and 143 deletions

View file

@ -161,16 +161,17 @@ class Mssql extends DboSource {
if (!$result) {
$result->closeCursor();
return array();
}
} else {
$tables = array();
$tables = array();
while ($line = $result->fetch(PDO::FETCH_ASSOC)) {
$tables[] = $line['TABLE_NAME'];
}
while ($line = $result->fetch()) {
$tables[] = $line[0];
}
$result->closeCursor();
parent::listSources($tables);
return $tables;
$result->closeCursor();
parent::listSources($tables);
return $tables;
}
}
/**
@ -197,7 +198,7 @@ class Mssql extends DboSource {
'type' => $this->column($column->Type),
'null' => ($column->Null === 'YES' ? true : false),
'default' => preg_replace("/^[(]{1,2}'?([^')]*)?'?[)]{1,2}$/", "$1", $column->Default),
'length' => intval($column->Type),
'length' => intval($column->Length),
'key' => ($column->Key == '1') ? 'primary' : false
);
@ -348,7 +349,7 @@ class Mssql extends DboSource {
if (!empty($values)) {
$fields = array_combine($fields, $values);
}
$primaryKey = $this->_getPrimaryKey($model);
$primaryKey = $this->_getPrimaryKey($model->schema());
if (array_key_exists($primaryKey, $fields)) {
if (empty($fields[$primaryKey])) {
@ -463,24 +464,24 @@ class Mssql extends DboSource {
$this->map = array();
$numFields = $results->columnCount();
$index = 0;
$j = 0;
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;
}
}
@ -608,9 +609,10 @@ class Mssql extends DboSource {
* @param string $table
* @param string $fields
* @param array $values
* @param array $schema
*/
public function insertMulti($table, $fields, $values) {
$primaryKey = $this->_getPrimaryKey($table);
public function insertMulti($table, $fields, $values, $schema) {
$primaryKey = $this->_getPrimaryKey($schema);
$hasPrimaryKey = $primaryKey != null && (
(is_array($fields) && in_array($primaryKey, $fields)
|| (is_string($fields) && strpos($fields, $this->startQuote . $primaryKey . $this->endQuote) !== false))
@ -619,7 +621,7 @@ class Mssql extends DboSource {
if ($hasPrimaryKey) {
$this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' ON');
}
parent::insertMulti($table, $fields, $values);
parent::insertMulti($table, $fields, $values, $schema);
if ($hasPrimaryKey) {
$this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' OFF');
}
@ -673,17 +675,11 @@ class Mssql extends DboSource {
/**
* Makes sure it will return the primary key
*
* @param mixed $model
* @param array $schema
* @access protected
* @return string
*/
function _getPrimaryKey($model) {
if (is_object($model)) {
$schema = $model->schema();
} else {
$schema = $this->describe($model);
}
function _getPrimaryKey($schema) {
foreach ($schema as $field => $props) {
if (isset($props['key']) && $props['key'] == 'primary') {
return $field;

View file

@ -2796,8 +2796,9 @@ class DboSource extends DataSource {
* @param string $table
* @param string $fields
* @param array $values
* @param array $schema
*/
public function insertMulti($table, $fields, $values) {
public function insertMulti($table, $fields, $values, $schema) {
$table = $this->fullTableName($table);
$holder = implode(',', array_fill(0, count($fields), '?'));
$fields = implode(', ', array_map(array(&$this, 'name'), $fields));

View file

@ -1522,7 +1522,7 @@ class Model extends Object {
}
if (!empty($newValues)) {
$db->insertMulti($this->{$join}, $fields, $newValues);
$db->insertMulti($this->{$join}, $fields, $newValues, $this->{$join}->schema());
}
}
}

View file

@ -36,19 +36,20 @@ class MssqlTestDb extends Mssql {
public $simulated = array();
/**
* simalate property
* simulate property
*
* @var array
* @access public
*/
public $simulate = true;
public $simulate = false;
/**
* fetchAllResultsStack
* execute results stack
*
* @var array
* @access public
*/
public $fetchAllResultsStack = array();
public $executeResultsStack = array();
/**
* execute method
@ -60,7 +61,7 @@ class MssqlTestDb extends Mssql {
function _execute($sql) {
if ($this->simulate) {
$this->simulated[] = $sql;
return null;
return empty($this->executeResultsStack) ? null : array_pop($this->executeResultsStack);
} else {
return parent::_execute($sql);
}
@ -77,21 +78,6 @@ class MssqlTestDb extends Mssql {
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
*
@ -105,12 +91,12 @@ class MssqlTestDb extends Mssql {
/**
* getPrimaryKey method
*
* @param mixed $model
* @param array $schema
* @access public
* @return void
*/
function getPrimaryKey($model) {
return parent::_getPrimaryKey($model);
function getPrimaryKey($schema) {
return parent::_getPrimaryKey($schema);
}
/**
* clearFieldMappings method
@ -211,17 +197,6 @@ class MssqlTestModel extends Model {
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;
}
}
/**
@ -258,6 +233,21 @@ class MssqlClientTestModel extends Model {
'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
);
}
/**
* MssqlTestResultIterator class
*
* @package cake.tests.cases.libs.model.datasources
*/
class MssqlTestResultIterator extends ArrayIterator {
/**
* closeCursor method
*
* @access public
*/
public function closeCursor() {}
}
/**
* MssqlTest class
*
@ -292,19 +282,15 @@ class MssqlTest extends CakeTestCase {
* Make sure all fixtures tables are being created
*
*/
public function start() {
$this->db->simulate = false;
parent::start();
public function startTest($method) {
$this->db->simulate = true;
}
/**
* Make sure all fixtures tables are being dropped
*
*/
public function end() {
public function endTest($method) {
$this->db->simulate = false;
parent::end();
$this->db->simulate = true;
}
/**
* Sets up a Dbo class instance for testing
@ -449,19 +435,17 @@ class MssqlTest extends CakeTestCase {
* @return void
*/
function testDescribe() {
$MssqlTableDescription = array(
0 => array(
0 => array(
'Default' => '((0))',
'Field' => 'count',
'Key' => 0,
'Length' => '4',
'Null' => 'NO',
'Type' => 'integer',
)
$MssqlTableDescription = new MssqlTestResultIterator(array(
(object) array(
'Default' => '((0))',
'Field' => 'count',
'Key' => 0,
'Length' => '4',
'Null' => 'NO',
'Type' => 'integer'
)
);
$this->db->fetchAllResultsStack = array($MssqlTableDescription);
));
$this->db->executeResultsStack = array($MssqlTableDescription);
$dummyModel = $this->model;
$result = $this->db->describe($dummyModel);
$expected = array(
@ -480,12 +464,12 @@ class MssqlTest extends CakeTestCase {
* @return unknown_type
*/
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);
@ -506,7 +490,7 @@ class MssqlTest 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);
@ -579,21 +563,13 @@ class MssqlTest extends CakeTestCase {
* @return void
*/
public function testGetPrimaryKey() {
// When param is a model
$result = $this->db->getPrimaryKey($this->model);
$this->assertEqual($result, 'id');
$schema = $this->model->schema();
unset($schema['id']['key']);
$this->model->setSchema($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');
$result = $this->db->getPrimaryKey($schema);
$this->assertEqual($result, 'id');
unset($schema['id']['key']);
$result = $this->db->getPrimaryKey($schema);
$this->assertNull($result);
}
/**
@ -603,51 +579,26 @@ class MssqlTest extends CakeTestCase {
*/
public function testInsertMulti() {
$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);
$this->db->insertMulti($this->model, $fields, $values, $this->model->schema());
$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'
);
$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);
$this->db->insertMulti($this->model, $fields, $values, $this->model->schema());
$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\')'
);
$expected = array();
$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

@ -397,6 +397,10 @@ class ModelReadTest extends BaseModelTest {
* @return void
*/
function testRecursiveUnbind() {
if ($this->skipIf($this->db instanceof Mssql, 'The test of testRecursiveUnbind test is not compatible with Mssql, because it check for time columns.')) {
return;
}
$this->loadFixtures('Apple', 'Sample');
$TestModel = new Apple();
$TestModel->recursive = 2;
@ -2992,7 +2996,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 +3655,10 @@ class ModelReadTest extends BaseModelTest {
* @return void
*/
function testFindCombinedRelations() {
if ($this->skipIf($this->db instanceof Mssql, 'The test of testRecursiveUnbind test is not compatible with Mssql, because it check for time columns.')) {
return;
}
$this->loadFixtures('Apple', 'Sample');
$TestModel = new Apple();
@ -6227,7 +6235,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 Mssql)) {
$result = $TestModel->find('all', array('limit' => 3, 'page' => 2));
$expected = array(
array(
@ -7398,10 +7406,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 Mssql)) {
$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 +7481,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

@ -211,7 +211,7 @@ class CakeTestFixture {
$fields = array_keys($record);
$values[] = array_values(array_merge($default, $record));
}
return $db->insertMulti($this->table, $fields, $values);
return $db->insertMulti($this->table, $fields, $values, $this->fields);
}
return true;
}