Merge branch 'feature/2.0/pdo' into 2.0-class-loading

This commit is contained in:
José Lorenzo Rodríguez 2010-12-04 11:21:54 -04:30
commit 8678661b9c
35 changed files with 5102 additions and 5813 deletions

View file

@ -299,7 +299,7 @@ class SchemaShell extends Shell {
* *
* @access private * @access private
*/ */
function __create(&$Schema, $table = null) { function __create($Schema, $table = null) {
$db = ConnectionManager::getDataSource($this->Schema->connection); $db = ConnectionManager::getDataSource($this->Schema->connection);
$drop = $create = array(); $drop = $create = array();

View file

@ -106,7 +106,7 @@ class DbConfigTask extends Shell {
} }
} }
$driver = $this->in('Driver:', array('db2', 'firebird', 'mssql', 'mysql', 'mysqli', 'odbc', 'oracle', 'postgres', 'sqlite', 'sybase'), 'mysql'); $driver = $this->in('Driver:', array('db2', 'firebird', 'mssql', 'mysql', 'odbc', 'oracle', 'postgres', 'sqlite', 'sybase'), 'mysql');
$persistent = $this->in('Persistent Connection?', array('y', 'n'), 'n'); $persistent = $this->in('Persistent Connection?', array('y', 'n'), 'n');
if (strtolower($persistent) == 'n') { if (strtolower($persistent) == 'n') {

View file

@ -31,7 +31,6 @@
* *
* driver => The name of a supported driver; valid options are as follows: * driver => The name of a supported driver; valid options are as follows:
* mysql - MySQL 4 & 5, * mysql - MySQL 4 & 5,
* mysqli - MySQL 4 & 5 Improved Interface (PHP5 only),
* sqlite - SQLite (PHP5 only), * sqlite - SQLite (PHP5 only),
* postgres - PostgreSQL 7 and higher, * postgres - PostgreSQL 7 and higher,
* mssql - Microsoft SQL Server 2000 and higher, * mssql - Microsoft SQL Server 2000 and higher,
@ -67,7 +66,7 @@
* 'public', DB2 defaults to empty. * 'public', DB2 defaults to empty.
* *
* encoding => * encoding =>
* For MySQL, MySQLi, Postgres and DB2, specifies the character encoding to use when connecting to the * For MySQL, Postgres and DB2, specifies the character encoding to use when connecting to the
* database. Uses database default. * database. Uses database default.
* *
*/ */

View file

@ -89,6 +89,7 @@ class TranslateBehavior extends ModelBehavior {
* @return array Modified query * @return array Modified query
*/ */
public function beforeFind(&$model, $query) { public function beforeFind(&$model, $query) {
$this->runtime[$model->alias]['virtualFields'] = $model->virtualFields;
$locale = $this->_getLocale($model); $locale = $this->_getLocale($model);
if (empty($locale)) { if (empty($locale)) {
return $query; return $query;
@ -115,48 +116,28 @@ class TranslateBehavior extends ModelBehavior {
); );
return $query; return $query;
} }
$autoFields = false;
if (empty($query['fields'])) {
$query['fields'] = array($model->alias.'.*');
$recursive = $model->recursive;
if (isset($query['recursive'])) {
$recursive = $query['recursive'];
}
if ($recursive >= 0) {
foreach (array('hasOne', 'belongsTo') as $type) {
foreach ($model->{$type} as $key => $value) {
if (empty($value['fields'])) {
$query['fields'][] = $key.'.*';
} else {
foreach ($value['fields'] as $field) {
$query['fields'][] = $key.'.'.$field;
}
}
}
}
}
$autoFields = true;
}
$fields = array_merge($this->settings[$model->alias], $this->runtime[$model->alias]['fields']); $fields = array_merge($this->settings[$model->alias], $this->runtime[$model->alias]['fields']);
$addFields = array(); $addFields = array();
if (is_array($query['fields'])) { if (empty($query['fields'])) {
$addFields = $fields;
} else if (is_array($query['fields'])) {
foreach ($fields as $key => $value) { foreach ($fields as $key => $value) {
$field = (is_numeric($key)) ? $value : $key; $field = (is_numeric($key)) ? $value : $key;
if (in_array($model->alias.'.*', $query['fields']) || $autoFields || in_array($model->alias.'.'.$field, $query['fields']) || in_array($field, $query['fields'])) { if (in_array($model->alias.'.*', $query['fields']) || in_array($model->alias.'.'.$field, $query['fields']) || in_array($field, $query['fields'])) {
$addFields[] = $field; $addFields[] = $field;
} }
} }
} }
$this->runtime[$model->alias]['virtualFields'] = $model->virtualFields;
if ($addFields) { if ($addFields) {
foreach ($addFields as $field) { foreach ($addFields as $_f => $field) {
foreach (array($field, $model->alias.'.'.$field) as $_field) { $aliasField = is_numeric($_f) ? $field : $_f;
$key = array_search($_field, $query['fields']);
foreach (array($aliasField, $model->alias.'.'.$aliasField) as $_field) {
$key = array_search($_field, (array)$query['fields']);
if ($key !== false) { if ($key !== false) {
unset($query['fields'][$key]); unset($query['fields'][$key]);
@ -165,7 +146,10 @@ class TranslateBehavior extends ModelBehavior {
if (is_array($locale)) { if (is_array($locale)) {
foreach ($locale as $_locale) { foreach ($locale as $_locale) {
$query['fields'][] = 'I18n__'.$field.'__'.$_locale.'.content'; $model->virtualFields['i18n_'.$field.'_'.$_locale] = 'I18n__'.$field.'__'.$_locale.'.content';
if (!empty($query['fields'])) {
$query['fields'][] = 'i18n_'.$field.'_'.$_locale;
}
$query['joins'][] = array( $query['joins'][] = array(
'type' => 'LEFT', 'type' => 'LEFT',
'alias' => 'I18n__'.$field.'__'.$_locale, 'alias' => 'I18n__'.$field.'__'.$_locale,
@ -173,13 +157,16 @@ class TranslateBehavior extends ModelBehavior {
'conditions' => array( 'conditions' => array(
$model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"), $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"),
'I18n__'.$field.'__'.$_locale.'.model' => $model->name, 'I18n__'.$field.'__'.$_locale.'.model' => $model->name,
'I18n__'.$field.'__'.$_locale.'.'.$RuntimeModel->displayField => $field, 'I18n__'.$field.'__'.$_locale.'.'.$RuntimeModel->displayField => $aliasField,
'I18n__'.$field.'__'.$_locale.'.locale' => $_locale 'I18n__'.$field.'__'.$_locale.'.locale' => $_locale
) )
); );
} }
} else { } else {
$query['fields'][] = 'I18n__'.$field.'.content'; $model->virtualFields['i18n_'.$field] = 'I18n__'.$field.'.content';
if (!empty($query['fields'])) {
$query['fields'][] = 'i18n_'.$field;
}
$query['joins'][] = array( $query['joins'][] = array(
'type' => 'LEFT', 'type' => 'LEFT',
'alias' => 'I18n__'.$field, 'alias' => 'I18n__'.$field,
@ -187,7 +174,7 @@ class TranslateBehavior extends ModelBehavior {
'conditions' => array( 'conditions' => array(
$model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"), $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"),
'I18n__'.$field.'.model' => $model->name, 'I18n__'.$field.'.model' => $model->name,
'I18n__'.$field.'.'.$RuntimeModel->displayField => $field 'I18n__'.$field.'.'.$RuntimeModel->displayField => $aliasField
) )
); );
@ -199,9 +186,6 @@ class TranslateBehavior extends ModelBehavior {
} }
} }
} }
if (is_array($query['fields'])) {
$query['fields'] = array_merge($query['fields']);
}
$this->runtime[$model->alias]['beforeFind'] = $addFields; $this->runtime[$model->alias]['beforeFind'] = $addFields;
return $query; return $query;
} }
@ -215,7 +199,8 @@ class TranslateBehavior extends ModelBehavior {
* @return array Modified results * @return array Modified results
*/ */
public function afterFind(&$model, $results, $primary) { public function afterFind(&$model, $results, $primary) {
$this->runtime[$model->alias]['fields'] = array(); $model->virtualFields = $this->runtime[$model->alias]['virtualFields'];
$this->runtime[$model->alias]['virtualFields'] = $this->runtime[$model->alias]['fields'] = array();
$locale = $this->_getLocale($model); $locale = $this->_getLocale($model);
if (empty($locale) || empty($results) || empty($this->runtime[$model->alias]['beforeFind'])) { if (empty($locale) || empty($results) || empty($this->runtime[$model->alias]['beforeFind'])) {
@ -223,28 +208,30 @@ class TranslateBehavior extends ModelBehavior {
} }
$beforeFind = $this->runtime[$model->alias]['beforeFind']; $beforeFind = $this->runtime[$model->alias]['beforeFind'];
foreach ($results as $key => $row) { foreach ($results as $key => &$row) {
$results[$key][$model->alias]['locale'] = (is_array($locale)) ? @$locale[0] : $locale; $results[$key][$model->alias]['locale'] = (is_array($locale)) ? current($locale) : $locale;
foreach ($beforeFind as $_f => $field) {
$aliasField = is_numeric($_f) ? $field : $_f;
foreach ($beforeFind as $field) {
if (is_array($locale)) { if (is_array($locale)) {
foreach ($locale as $_locale) { foreach ($locale as $_locale) {
if (!isset($results[$key][$model->alias][$field]) && !empty($results[$key]['I18n__'.$field.'__'.$_locale]['content'])) { if (!isset($row[$model->alias][$aliasField]) && !empty($row[$model->alias]['i18n_'.$field.'_'.$_locale])) {
$results[$key][$model->alias][$field] = $results[$key]['I18n__'.$field.'__'.$_locale]['content']; $row[$model->alias][$aliasField] = $row[$model->alias]['i18n_'.$field.'_'.$_locale];
$row[$model->alias]['locale'] = $_locale;
} }
unset($results[$key]['I18n__'.$field.'__'.$_locale]); unset($row[$model->alias]['i18n_'.$field.'_'.$_locale]);
} }
if (!isset($results[$key][$model->alias][$field])) { if (!isset($row[$model->alias][$aliasField])) {
$results[$key][$model->alias][$field] = ''; $row[$model->alias][$aliasField] = '';
} }
} else { } else {
$value = ''; $value = '';
if (!empty($results[$key]['I18n__'.$field]['content'])) { if (!empty($row[$model->alias]['i18n_' . $field])) {
$value = $results[$key]['I18n__'.$field]['content']; $value = $row[$model->alias]['i18n_' . $field];
} }
$results[$key][$model->alias][$field] = $value; $row[$model->alias][$aliasField] = $value;
unset($results[$key]['I18n__'.$field]); unset($row[$model->alias]['i18n_' . $field]);
} }
} }
} }
@ -380,8 +367,7 @@ class TranslateBehavior extends ModelBehavior {
} elseif (empty($model->translateTable) && empty($model->translateModel)) { } elseif (empty($model->translateTable) && empty($model->translateModel)) {
$this->runtime[$model->alias]['model']->setSource('i18n'); $this->runtime[$model->alias]['model']->setSource('i18n');
} }
$model =& $this->runtime[$model->alias]['model']; return $this->runtime[$model->alias]['model'];
return $model;
} }
/** /**

View file

@ -65,7 +65,7 @@ class TreeBehavior extends ModelBehavior {
if (in_array($settings['scope'], $Model->getAssociated('belongsTo'))) { if (in_array($settings['scope'], $Model->getAssociated('belongsTo'))) {
$data = $Model->getAssociated($settings['scope']); $data = $Model->getAssociated($settings['scope']);
$parent =& $Model->{$settings['scope']}; $parent = $Model->{$settings['scope']};
$settings['scope'] = $Model->alias . '.' . $data['foreignKey'] . ' = ' . $parent->alias . '.' . $parent->primaryKey; $settings['scope'] = $Model->alias . '.' . $data['foreignKey'] . ' = ' . $parent->alias . '.' . $parent->primaryKey;
$settings['recursive'] = 0; $settings['recursive'] = 0;
} }
@ -599,7 +599,7 @@ class TreeBehavior extends ModelBehavior {
$this->_setParent($Model, $array[$Model->alias][$parent]); $this->_setParent($Model, $array[$Model->alias][$parent]);
} }
} else { } else {
$db =& ConnectionManager::getDataSource($Model->useDbConfig); $db = ConnectionManager::getDataSource($Model->useDbConfig);
foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey, $parent), 'order' => $left)) as $array) { foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey, $parent), 'order' => $left)) as $array) {
$path = $this->getPath($Model, $array[$Model->alias][$Model->primaryKey]); $path = $this->getPath($Model, $array[$Model->alias][$Model->primaryKey]);
if ($path == null || count($path) < 2) { if ($path == null || count($path) < 2) {
@ -702,7 +702,7 @@ class TreeBehavior extends ModelBehavior {
$parentNode[$right] = $node[$right] + 1; $parentNode[$right] = $node[$right] + 1;
} }
$db =& ConnectionManager::getDataSource($Model->useDbConfig); $db = ConnectionManager::getDataSource($Model->useDbConfig);
$Model->updateAll( $Model->updateAll(
array($parent => $db->value($node[$parent], $parent)), array($parent => $db->value($node[$parent], $parent)),
array($Model->escapeField($parent) => $node[$Model->primaryKey]) array($Model->escapeField($parent) => $node[$Model->primaryKey])
@ -888,7 +888,7 @@ class TreeBehavior extends ModelBehavior {
* @access private * @access private
*/ */
function __getMax($Model, $scope, $right, $recursive = -1, $created = false) { function __getMax($Model, $scope, $right, $recursive = -1, $created = false) {
$db =& ConnectionManager::getDataSource($Model->useDbConfig); $db = ConnectionManager::getDataSource($Model->useDbConfig);
if ($created) { if ($created) {
if (is_string($scope)) { if (is_string($scope)) {
$scope .= " AND {$Model->alias}.{$Model->primaryKey} <> "; $scope .= " AND {$Model->alias}.{$Model->primaryKey} <> ";
@ -916,7 +916,7 @@ class TreeBehavior extends ModelBehavior {
* @access private * @access private
*/ */
function __getMin($Model, $scope, $left, $recursive = -1) { function __getMin($Model, $scope, $left, $recursive = -1) {
$db =& ConnectionManager::getDataSource($Model->useDbConfig); $db = ConnectionManager::getDataSource($Model->useDbConfig);
$name = $Model->alias . '.' . $left; $name = $Model->alias . '.' . $left;
list($edge) = array_values($Model->find('first', array( list($edge) = array_values($Model->find('first', array(
'conditions' => $scope, 'conditions' => $scope,

View file

@ -95,11 +95,7 @@ class CakeSchema extends Object {
} }
if (empty($options['path'])) { if (empty($options['path'])) {
if (is_dir(CONFIGS . 'schema')) { $this->path = CONFIGS . 'schema';
$this->path = CONFIGS . 'schema';
} else {
$this->path = CONFIGS . 'sql';
}
} }
$options = array_merge(get_object_vars($this), $options); $options = array_merge(get_object_vars($this), $options);
@ -161,7 +157,7 @@ class CakeSchema extends Object {
* @param array $options schema object properties * @param array $options schema object properties
* @return array Set of name and tables * @return array Set of name and tables
*/ */
public function &load($options = array()) { public function load($options = array()) {
if (is_string($options)) { if (is_string($options)) {
$options = array('path' => $options); $options = array('path' => $options);
} }
@ -183,8 +179,8 @@ class CakeSchema extends Object {
$Schema = new $class($options); $Schema = new $class($options);
return $Schema; return $Schema;
} }
$false = false;
return $false; return false;
} }
/** /**
@ -299,7 +295,9 @@ class CakeSchema extends Object {
$systemTables = array( $systemTables = array(
'aros', 'acos', 'aros_acos', Configure::read('Session.table'), 'i18n' 'aros', 'acos', 'aros_acos', Configure::read('Session.table'), 'i18n'
); );
if (get_class($Object) === 'AppModel') {
continue;
}
if (in_array($table, $systemTables)) { if (in_array($table, $systemTables)) {
$tables[$Object->table] = $this->__columns($Object); $tables[$Object->table] = $this->__columns($Object);
$tables[$Object->table]['indexes'] = $db->index($Object); $tables[$Object->table]['indexes'] = $db->index($Object);

View file

@ -19,19 +19,42 @@
*/ */
/** /**
* Provides common base for MySQL & MySQLi connections * MySQL DBO driver object
*
* Provides connection and SQL generation for MySQL RDMS
* *
* @package cake * @package cake
* @subpackage cake.cake.libs.model.datasources.dbo * @subpackage cake.cake.libs.model.datasources.dbo
*/ */
class DboMysqlBase extends DboSource { class DboMysql extends DboSource {
/** /**
* Description property. * Datasource description
* *
* @var string * @var string
*/ */
public $description = "MySQL DBO Base Driver"; public $description = "MySQL DBO Driver";
/**
* Base configuration settings for MySQL driver
*
* @var array
*/
protected $_baseConfig = array(
'persistent' => true,
'host' => 'localhost',
'login' => 'root',
'password' => '',
'database' => 'cake',
'port' => '3306'
);
/**
* Reference to the PDO object connection
*
* @var PDO $_connection
*/
protected $_connection = null;
/** /**
* Start quote * Start quote
@ -110,49 +133,190 @@ class DboMysqlBase extends DboSource {
'boolean' => array('name' => 'tinyint', 'limit' => '1') 'boolean' => array('name' => 'tinyint', 'limit' => '1')
); );
/**
* Connects to the database using options in the given configuration array.
*
* @return boolean True if the database could be connected, else false
*/
function connect() {
$config = $this->config;
$this->connected = false;
try {
$flags = array(
PDO::ATTR_PERSISTENT => $config['persistent'],
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
);
if (!empty($config['encoding'])) {
$flags[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $config['encoding'];
}
$this->_connection = new PDO(
"mysql:{$config['host']};port={$config['port']};dbname={$config['database']}",
$config['login'],
$config['password'],
$flags
);
$this->connected = true;
} catch (PDOException $e) {
$this->errors[] = $e->getMessage();
}
$this->_useAlias = (bool)version_compare($this->getVersion(), "4.1", ">=");
return $this->connected;
}
/**
* Check whether the MySQL extension is installed/loaded
*
* @return boolean
*/
function enabled() {
return in_array('mysql', PDO::getAvailableDrivers());
}
/**
* Returns an array of sources (tables) in the database.
*
* @return array Array of tablenames in the database
*/
function listSources($data = null) {
$cache = parent::listSources();
if ($cache != null) {
return $cache;
}
$result = $this->_execute('SHOW TABLES FROM ' . $this->config['database']);
if (!$result) {
$result->closeCursor();
return array();
} else {
$tables = array();
while ($line = $result->fetch()) {
$tables[] = $line[0];
}
$result->closeCursor();
parent::listSources($tables);
return $tables;
}
}
/**
* Builds a map of the columns contained in a result
*
* @param PDOStatement $results
*/
function resultSet($results) {
$this->map = array();
$numFields = $results->columnCount();
$index = 0;
$j = 0;
while ($j < $numFields) {
$column = $results->getColumnMeta($j);
if (!empty($column['table']) && strpos($column['name'], $this->virtualFieldSeparator) === false) {
$this->map[$index++] = array($column['table'], $column['name']);
} else {
$this->map[$index++] = array(0, $column['name']);
}
$j++;
}
}
/**
* Fetches the next row from the current result set
*
* @return mixed array with results fetched and mapped to column names or false if there is no results left to fetch
*/
function fetchResult() {
if ($row = $this->_result->fetch()) {
$resultRow = array();
foreach ($this->map as $col => $meta) {
list($table, $column) = $meta;
$resultRow[$table][$column] = $row[$col];
}
return $resultRow;
} else {
$this->_result->closeCursor();
return false;
}
}
/**
* Gets the database encoding
*
* @return string The database encoding
*/
public function getEncoding() {
return $this->_execute('SHOW VARIABLES LIKE ?', array('character_set_client'))->fetchObject()->Value;
}
/**
* Gets the version string of the database server
*
* @return string The database encoding
*/
public function getVersion() {
return $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION);
}
/**
* Query charset by collation
*
* @param string $name Collation name
* @return string Character set name
*/
public function getCharsetName($name) {
if ((bool)version_compare($this->getVersion(), "5", ">=")) {
$r = $this->_execute('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME = ?', array($name));
$cols = $r->fetch();
if (isset($cols['CHARACTER_SET_NAME'])) {
return $cols['CHARACTER_SET_NAME'];
}
}
return false;
}
/** /**
* Returns an array of the fields in given table name. * Returns an array of the fields in given table name.
* *
* @param string $tableName Name of database table to inspect * @param mixed $tableName Name of database table to inspect or model instance
* @return array Fields in table. Keys are name and type * @return array Fields in table. Keys are name and type
*/ */
function describe(&$model) { function describe($model) {
$cache = parent::describe($model); $cache = parent::describe($model);
if ($cache != null) { if ($cache != null) {
return $cache; return $cache;
} }
$fields = false; $fields = false;
$cols = $this->query('SHOW FULL COLUMNS FROM ' . $this->fullTableName($model)); $cols = $this->_execute('SHOW FULL COLUMNS FROM ' . $this->fullTableName($model));
foreach ($cols as $column) { foreach ($cols as $column) {
$colKey = array_keys($column); $fields[$column->Field] = array(
if (isset($column[$colKey[0]]) && !isset($column[0])) { 'type' => $this->column($column->Type),
$column[0] = $column[$colKey[0]]; 'null' => ($column->Null == 'YES' ? true : false),
'default' => $column->Default,
'length' => $this->length($column->Type),
);
if (!empty($column->Key) && isset($this->index[$column->Key])) {
$fields[$column->Field]['key'] = $this->index[$column->Key];
} }
if (isset($column[0])) { foreach ($this->fieldParameters as $name => $value) {
$fields[$column[0]['Field']] = array( if (!empty($column->{$value['column']})) {
'type' => $this->column($column[0]['Type']), $fields[$column->Field][$name] = $column->{$value['column']};
'null' => ($column[0]['Null'] == 'YES' ? true : false),
'default' => $column[0]['Default'],
'length' => $this->length($column[0]['Type']),
);
if (!empty($column[0]['Key']) && isset($this->index[$column[0]['Key']])) {
$fields[$column[0]['Field']]['key'] = $this->index[$column[0]['Key']];
} }
foreach ($this->fieldParameters as $name => $value) { }
if (!empty($column[0][$value['column']])) { if (isset($fields[$column->Field]['collate'])) {
$fields[$column[0]['Field']][$name] = $column[0][$value['column']]; $charset = $this->getCharsetName($fields[$column->Field]['collate']);
} if ($charset) {
} $fields[$column->Field]['charset'] = $charset;
if (isset($fields[$column[0]['Field']]['collate'])) {
$charset = $this->getCharsetName($fields[$column[0]['Field']]['collate']);
if ($charset) {
$fields[$column[0]['Field']]['charset'] = $charset;
}
} }
} }
} }
$this->__cacheDescription($this->fullTableName($model, false), $fields); $this->__cacheDescription($this->fullTableName($model, false), $fields);
$cols->closeCursor();
return $fields; return $fields;
} }
@ -249,26 +413,26 @@ class DboMysqlBase extends DboSource {
function index($model) { function index($model) {
$index = array(); $index = array();
$table = $this->fullTableName($model); $table = $this->fullTableName($model);
$old = version_compare($this->getVersion(), '4.1', '<=');
if ($table) { if ($table) {
$indexes = $this->query('SHOW INDEX FROM ' . $table); $indices = $this->_execute('SHOW INDEX FROM ' . $table);
if (isset($indexes[0]['STATISTICS'])) { while ($idx = $indices->fetch()) {
$keys = Set::extract($indexes, '{n}.STATISTICS'); if ($old) {
} else { $idx = (object) current((array)$idx);
$keys = Set::extract($indexes, '{n}.0'); }
} if (!isset($index[$idx->Key_name]['column'])) {
foreach ($keys as $i => $key) {
if (!isset($index[$key['Key_name']])) {
$col = array(); $col = array();
$index[$key['Key_name']]['column'] = $key['Column_name']; $index[$idx->Key_name]['column'] = $idx->Column_name;
$index[$key['Key_name']]['unique'] = intval($key['Non_unique'] == 0); $index[$idx->Key_name]['unique'] = intval($idx->Non_unique == 0);
} else { } else {
if (!is_array($index[$key['Key_name']]['column'])) { if (!empty($index[$idx->Key_name]['column']) && !is_array($index[$idx->Key_name]['column'])) {
$col[] = $index[$key['Key_name']]['column']; $col[] = $index[$idx->Key_name]['column'];
} }
$col[] = $key['Column_name']; $col[] = $idx->Column_name;
$index[$key['Key_name']]['column'] = $col; $index[$idx->Key_name]['column'] = $col;
} }
} }
$indices->closeCursor();
} }
return $index; return $index;
} }
@ -412,21 +576,6 @@ class DboMysqlBase extends DboSource {
return $alter; return $alter;
} }
/**
* Inserts multiple values into a table
*
* @param string $table
* @param string $fields
* @param array $values
*/
function insertMulti($table, $fields, $values) {
$table = $this->fullTableName($table);
if (is_array($fields)) {
$fields = implode(', ', array_map(array(&$this, 'name'), $fields));
}
$values = implode(', ', $values);
$this->query("INSERT INTO {$table} ({$fields}) VALUES {$values}");
}
/** /**
* Returns an detailed array of sources (tables) in the database. * Returns an detailed array of sources (tables) in the database.
* *
@ -435,23 +584,29 @@ class DboMysqlBase extends DboSource {
*/ */
function listDetailedSources($name = null) { function listDetailedSources($name = null) {
$condition = ''; $condition = '';
$params = array();
if (is_string($name)) { if (is_string($name)) {
$condition = ' LIKE ' . $this->value($name); $condition = ' WHERE name = ?' ;
$params = array($name);
} }
$result = $this->query('SHOW TABLE STATUS FROM ' . $this->name($this->config['database']) . $condition . ';'); $result = $this->_execute('SHOW TABLE STATUS ' . $condition, $params);
if (!$result) { if (!$result) {
$result->closeCursor();
return array(); return array();
} else { } else {
$tables = array(); $tables = array();
foreach ($result as $row) { while ($row = $result->fetch()) {
$tables[$row['TABLES']['Name']] = $row['TABLES']; $tables[$row->Name] = (array) $row;
if (!empty($row['TABLES']['Collation'])) { unset($tables[$row->Name]['queryString']);
$charset = $this->getCharsetName($row['TABLES']['Collation']); if (!empty($row->Collation)) {
$charset = $this->getCharsetName($row->Collation);
if ($charset) { if ($charset) {
$tables[$row['TABLES']['Name']]['charset'] = $charset; $tables[$row->Name]['charset'] = $charset;
} }
} }
} }
$result->closeCursor();
if (is_string($name)) { if (is_string($name)) {
return $tables[$name]; return $tables[$name];
} }
@ -507,292 +662,3 @@ class DboMysqlBase extends DboSource {
return 'text'; return 'text';
} }
} }
/**
* MySQL DBO driver object
*
* Provides connection and SQL generation for MySQL RDMS
*
* @package cake
* @subpackage cake.cake.libs.model.datasources.dbo
*/
class DboMysql extends DboMysqlBase {
/**
* Datasource description
*
* @var string
*/
public $description = "MySQL DBO Driver";
/**
* Base configuration settings for MySQL driver
*
* @var array
*/
protected $_baseConfig = array(
'persistent' => true,
'host' => 'localhost',
'login' => 'root',
'password' => '',
'database' => 'cake',
'port' => '3306'
);
/**
* Connects to the database using options in the given configuration array.
*
* @return boolean True if the database could be connected, else false
*/
function connect() {
$config = $this->config;
$this->connected = false;
if (!$config['persistent']) {
$this->connection = mysql_connect($config['host'] . ':' . $config['port'], $config['login'], $config['password'], true);
$config['connect'] = 'mysql_connect';
} else {
$this->connection = mysql_pconnect($config['host'] . ':' . $config['port'], $config['login'], $config['password']);
}
if (mysql_select_db($config['database'], $this->connection)) {
$this->connected = true;
}
if (!empty($config['encoding'])) {
$this->setEncoding($config['encoding']);
}
$this->_useAlias = (bool)version_compare(mysql_get_server_info($this->connection), "4.1", ">=");
return $this->connected;
}
/**
* Check whether the MySQL extension is installed/loaded
*
* @return boolean
*/
function enabled() {
return extension_loaded('mysql');
}
/**
* Disconnects from database.
*
* @return boolean True if the database could be disconnected, else false
*/
function disconnect() {
if (isset($this->results) && is_resource($this->results)) {
mysql_free_result($this->results);
}
$this->connected = !@mysql_close($this->connection);
return !$this->connected;
}
/**
* Executes given SQL statement.
*
* @param string $sql SQL statement
* @return resource Result resource identifier
*/
protected function _execute($sql) {
return mysql_query($sql, $this->connection);
}
/**
* Returns an array of sources (tables) in the database.
*
* @return array Array of tablenames in the database
*/
function listSources() {
$cache = parent::listSources();
if ($cache != null) {
return $cache;
}
$result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']) . ';');
if (!$result) {
return array();
} else {
$tables = array();
while ($line = mysql_fetch_row($result)) {
$tables[] = $line[0];
}
parent::listSources($tables);
return $tables;
}
}
/**
* Returns a quoted and escaped string of $data for use in an SQL statement.
*
* @param string $data String to be prepared for use in an SQL statement
* @param string $column The column into which this data will be inserted
* @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) {
$parent = parent::value($data, $column, $safe);
if ($parent != null) {
return $parent;
}
if ($data === null || (is_array($data) && empty($data))) {
return 'NULL';
}
if ($data === '' && $column !== 'integer' && $column !== 'float' && $column !== 'boolean') {
return "''";
}
if (empty($column)) {
$column = $this->introspectType($data);
}
switch ($column) {
case 'boolean':
return $this->boolean((bool)$data);
break;
case 'integer':
case 'float':
if ($data === '') {
return 'NULL';
}
if (is_float($data)) {
return sprintf('%F', $data);
}
if ((is_int($data) || $data === '0') || (
is_numeric($data) && strpos($data, ',') === false &&
$data[0] != '0' && strpos($data, 'e') === false)
) {
return $data;
}
default:
return "'" . mysql_real_escape_string($data, $this->connection) . "'";
break;
}
}
/**
* Returns a formatted error message from previous database operation.
*
* @return string Error message with error number
*/
function lastError() {
if (mysql_errno($this->connection)) {
return mysql_errno($this->connection).': '.mysql_error($this->connection);
}
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 mysql_affected_rows($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->hasResult()) {
return mysql_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 LAST_INSERT_ID() AS insertID', false);
if ($id !== false && !empty($id) && !empty($id[0]) && isset($id[0]['insertID'])) {
return $id[0]['insertID'];
}
return null;
}
/**
* Enter description here...
*
* @param unknown_type $results
*/
function resultSet(&$results) {
if (isset($this->results) && is_resource($this->results) && $this->results != $results) {
mysql_free_result($this->results);
}
$this->results =& $results;
$this->map = array();
$numFields = mysql_num_fields($results);
$index = 0;
$j = 0;
while ($j < $numFields) {
$column = mysql_fetch_field($results, $j);
if (!empty($column->table) && strpos($column->name, $this->virtualFieldSeparator) === false) {
$this->map[$index++] = array($column->table, $column->name);
} else {
$this->map[$index++] = array(0, $column->name);
}
$j++;
}
}
/**
* Fetches the next row from the current result set
*
* @return unknown
*/
function fetchResult() {
if ($row = mysql_fetch_row($this->results)) {
$resultRow = array();
$i = 0;
foreach ($row as $index => $field) {
list($table, $column) = $this->map[$index];
$resultRow[$table][$column] = $row[$index];
$i++;
}
return $resultRow;
} else {
return false;
}
}
/**
* Gets the database encoding
*
* @return string The database encoding
*/
function getEncoding() {
return mysql_client_encoding($this->connection);
}
/**
* Query charset by collation
*
* @param string $name Collation name
* @return string Character set name
*/
function getCharsetName($name) {
if ((bool)version_compare(mysql_get_server_info($this->connection), "5", ">=")) {
$cols = $this->query('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME= ' . $this->value($name) . ';');
if (isset($cols[0]['COLLATIONS']['CHARACTER_SET_NAME'])) {
return $cols[0]['COLLATIONS']['CHARACTER_SET_NAME'];
}
}
return false;
}
}

View file

@ -1,336 +0,0 @@
<?php
/**
* MySQLi layer for DBO
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.libs.model.datasources.dbo
* @since CakePHP(tm) v 1.1.4.2974
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Datasource', 'DboMysql');
/**
* MySQLi DBO driver object
*
* Provides connection and SQL generation for MySQL RDMS using PHP's MySQLi Interface
*
* @package cake
* @subpackage cake.cake.libs.model.datasources.dbo
*/
class DboMysqli extends DboMysqlBase {
/**
* Datasource Description
*
* @var string
*/
public $description = "Mysqli DBO Driver";
/**
* Base configuration settings for Mysqli driver
*
* @var array
*/
protected $_baseConfig = array(
'persistent' => true,
'host' => 'localhost',
'login' => 'root',
'password' => '',
'database' => 'cake',
'port' => '3306'
);
/**
* Connects to the database using options in the given configuration array.
*
* @return boolean True if the database could be connected, else false
*/
function connect() {
$config = $this->config;
$this->connected = false;
if (is_numeric($config['port'])) {
$config['socket'] = null;
} else {
$config['socket'] = $config['port'];
$config['port'] = null;
}
$this->connection = mysqli_connect($config['host'], $config['login'], $config['password'], $config['database'], $config['port'], $config['socket']);
if ($this->connection !== false) {
$this->connected = true;
}
$this->_useAlias = (bool)version_compare(mysqli_get_server_info($this->connection), "4.1", ">=");
if (!empty($config['encoding'])) {
$this->setEncoding($config['encoding']);
}
return $this->connected;
}
/**
* Check that MySQLi is installed/enabled
*
* @return boolean
*/
function enabled() {
return extension_loaded('mysqli');
}
/**
* Disconnects from database.
*
* @return boolean True if the database could be disconnected, else false
*/
function disconnect() {
if (isset($this->results) && is_resource($this->results)) {
mysqli_free_result($this->results);
}
$this->connected = !@mysqli_close($this->connection);
return !$this->connected;
}
/**
* Executes given SQL statement.
*
* @param string $sql SQL statement
* @return resource Result resource identifier
*/
protected function _execute($sql) {
if (preg_match('/^\s*call/i', $sql)) {
return $this->_executeProcedure($sql);
}
return mysqli_query($this->connection, $sql);
}
/**
* Executes given SQL statement (procedure call).
*
* @param string $sql SQL statement (procedure call)
* @return resource Result resource identifier for first recordset
*/
protected function _executeProcedure($sql) {
$answer = mysqli_multi_query($this->connection, $sql);
$firstResult = mysqli_store_result($this->connection);
if (mysqli_more_results($this->connection)) {
while ($lastResult = mysqli_next_result($this->connection));
}
return $firstResult;
}
/**
* Returns an array of sources (tables) in the database.
*
* @return array Array of tablenames in the database
*/
function listSources() {
$cache = parent::listSources();
if ($cache !== null) {
return $cache;
}
$result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']) . ';');
if (!$result) {
return array();
}
$tables = array();
while ($line = mysqli_fetch_row($result)) {
$tables[] = $line[0];
}
parent::listSources($tables);
return $tables;
}
/**
* Returns a quoted and escaped string of $data for use in an SQL statement.
*
* @param string $data String to be prepared for use in an SQL statement
* @param string $column The column into which this data will be inserted
* @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) {
$parent = parent::value($data, $column, $safe);
if ($parent != null) {
return $parent;
}
if ($data === null || (is_array($data) && empty($data))) {
return 'NULL';
}
if ($data === '' && $column !== 'integer' && $column !== 'float' && $column !== 'boolean') {
return "''";
}
if (empty($column)) {
$column = $this->introspectType($data);
}
switch ($column) {
case 'boolean':
return $this->boolean((bool)$data);
break;
case 'integer' :
case 'float' :
case null :
if ($data === '') {
return 'NULL';
}
if ((is_int($data) || is_float($data) || $data === '0') || (
is_numeric($data) && strpos($data, ',') === false &&
$data[0] != '0' && strpos($data, 'e') === false)) {
return $data;
}
default:
$data = "'" . mysqli_real_escape_string($this->connection, $data) . "'";
break;
}
return $data;
}
/**
* Returns a formatted error message from previous database operation.
*
* @return string Error message with error number
*/
function lastError() {
if (mysqli_errno($this->connection)) {
return mysqli_errno($this->connection).': '.mysqli_error($this->connection);
}
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 mysqli_affected_rows($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->hasResult()) {
return mysqli_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 LAST_INSERT_ID() AS insertID', false);
if ($id !== false && !empty($id) && !empty($id[0]) && isset($id[0]['insertID'])) {
return $id[0]['insertID'];
}
return null;
}
/**
* Enter description here...
*
* @param unknown_type $results
*/
function resultSet(&$results) {
if (isset($this->results) && is_resource($this->results) && $this->results != $results) {
mysqli_free_result($this->results);
}
$this->results =& $results;
$this->map = array();
$numFields = mysqli_num_fields($results);
$index = 0;
$j = 0;
while ($j < $numFields) {
$column = mysqli_fetch_field_direct($results, $j);
if (!empty($column->table)) {
$this->map[$index++] = array($column->table, $column->name);
} else {
$this->map[$index++] = array(0, $column->name);
}
$j++;
}
}
/**
* Fetches the next row from the current result set
*
* @return unknown
*/
function fetchResult() {
if ($row = mysqli_fetch_row($this->results)) {
$resultRow = array();
foreach ($row as $index => $field) {
$table = $column = null;
if (count($this->map[$index]) === 2) {
list($table, $column) = $this->map[$index];
}
$resultRow[$table][$column] = $row[$index];
}
return $resultRow;
}
return false;
}
/**
* Gets the database encoding
*
* @return string The database encoding
*/
function getEncoding() {
return mysqli_client_encoding($this->connection);
}
/**
* Query charset by collation
*
* @param string $name Collation name
* @return string Character set name
*/
function getCharsetName($name) {
if ((bool)version_compare(mysqli_get_server_info($this->connection), "5", ">=")) {
$cols = $this->query('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME= ' . $this->value($name) . ';');
if (isset($cols[0]['COLLATIONS']['CHARACTER_SET_NAME'])) {
return $cols[0]['COLLATIONS']['CHARACTER_SET_NAME'];
}
}
return false;
}
/**
* Checks if the result is valid
*
* @return boolean True if the result is valid, else false
*/
function hasResult() {
return is_object($this->_result);
}
}

View file

@ -112,23 +112,29 @@ class DboPostgres extends DboSource {
*/ */
function connect() { function connect() {
$config = $this->config; $config = $this->config;
$conn = "host='{$config['host']}' port='{$config['port']}' dbname='{$config['database']}' ";
$conn .= "user='{$config['login']}' password='{$config['password']}'";
if (!$config['persistent']) {
$this->connection = pg_connect($conn, PGSQL_CONNECT_FORCE_NEW);
} else {
$this->connection = pg_pconnect($conn);
}
$this->connected = false; $this->connected = false;
try {
$flags = array(
PDO::ATTR_PERSISTENT => $config['persistent']
);
$this->_connection = new PDO(
"pgsql:host={$config['host']};port={$config['port']};dbname={$config['database']}",
$config['login'],
$config['password'],
$flags
);
if ($this->connection) {
$this->connected = true; $this->connected = true;
$this->_execute("SET search_path TO " . $config['schema']); if (!empty($config['encoding'])) {
} $this->setEncoding($config['encoding']);
if (!empty($config['encoding'])) { }
$this->setEncoding($config['encoding']); if (!empty($config['schema'])) {
$this->_execute('SET search_path TO ' . $config['schema']);
}
} catch (PDOException $e) {
$this->errors[] = $e->getMessage();
} }
return $this->connected; return $this->connected;
} }
@ -138,33 +144,7 @@ class DboPostgres extends DboSource {
* @return boolean * @return boolean
*/ */
function enabled() { function enabled() {
return extension_loaded('pgsql'); return in_array('pgsql', PDO::getAvailableDrivers());
}
/**
* Disconnects from database.
*
* @return boolean True if the database could be disconnected, else false
*/
function disconnect() {
if ($this->hasResult()) {
pg_free_result($this->_result);
}
if (is_resource($this->connection)) {
$this->connected = !pg_close($this->connection);
} else {
$this->connected = false;
}
return !$this->connected;
}
/**
* Executes given SQL statement.
*
* @param string $sql SQL statement
* @return resource Result resource identifier
*/
function _execute($sql) {
return pg_query($this->connection, $sql);
} }
/** /**
@ -180,18 +160,20 @@ class DboPostgres extends DboSource {
} }
$schema = $this->config['schema']; $schema = $this->config['schema'];
$sql = "SELECT table_name as name FROM INFORMATION_SCHEMA.tables WHERE table_schema = '{$schema}';"; $sql = "SELECT table_name as name FROM INFORMATION_SCHEMA.tables WHERE table_schema = ?";
$result = $this->fetchAll($sql, false); $result = $this->_execute($sql, array($schema));
if (!$result) { if (!$result) {
$result->closeCursor();
return array(); return array();
} else { } else {
$tables = array(); $tables = array();
foreach ($result as $item) { foreach ($result as $item) {
$tables[] = $item[0]['name']; $tables[] = $item->name;
} }
$result->closeCursor();
parent::listSources($tables); parent::listSources($tables);
return $tables; return $tables;
} }
@ -209,61 +191,56 @@ class DboPostgres extends DboSource {
$this->_sequenceMap[$table] = array(); $this->_sequenceMap[$table] = array();
if ($fields === null) { if ($fields === null) {
$cols = $this->fetchAll( $cols = $this->_execute(
"SELECT DISTINCT column_name AS name, data_type AS type, is_nullable AS null, "SELECT DISTINCT column_name AS name, data_type AS type, is_nullable AS null,
column_default AS default, ordinal_position AS position, character_maximum_length AS char_length, column_default AS default, ordinal_position AS position, character_maximum_length AS char_length,
character_octet_length AS oct_length FROM information_schema.columns character_octet_length AS oct_length FROM information_schema.columns
WHERE table_name = " . $this->value($table) . " AND table_schema = " . WHERE table_name = ? AND table_schema = ? ORDER BY position",
$this->value($this->config['schema'])." ORDER BY position", array($table, $this->config['schema'])
false
); );
foreach ($cols as $column) { foreach ($cols as $c) {
$colKey = array_keys($column); $type = $c->type;
if (!empty($c->oct_length) && $c->char_length === null) {
if (isset($column[$colKey[0]]) && !isset($column[0])) { if ($c->type == 'character varying') {
$column[0] = $column[$colKey[0]]; $length = null;
} $type = 'text';
if (isset($column[0])) {
$c = $column[0];
if (!empty($c['char_length'])) {
$length = intval($c['char_length']);
} elseif (!empty($c['oct_length'])) {
if ($c['type'] == 'character varying') {
$length = null;
$c['type'] = 'text';
} else {
$length = intval($c['oct_length']);
}
} else { } else {
$length = $this->length($c['type']); $length = intval($c->oct_length);
} }
$fields[$c['name']] = array( } elseif (!empty($c->char_length)) {
'type' => $this->column($c['type']), $length = intval($c->char_length);
'null' => ($c['null'] == 'NO' ? false : true), } else {
'default' => preg_replace( $length = $this->length($c->type);
"/^'(.*)'$/", }
"$1", if (empty($length)) {
preg_replace('/::.*/', '', $c['default']) $length = null;
), }
'length' => $length $fields[$c->name] = array(
); 'type' => $this->column($type),
if ($c['name'] == $model->primaryKey) { 'null' => ($c->null == 'NO' ? false : true),
$fields[$c['name']]['key'] = 'primary'; 'default' => preg_replace(
if ($fields[$c['name']]['type'] !== 'string') { "/^'(.*)'$/",
$fields[$c['name']]['length'] = 11; "$1",
preg_replace('/::.*/', '', $c->default)
),
'length' => $length
);
if ($model instanceof Model) {
if ($c->name == $model->primaryKey) {
$fields[$c->name]['key'] = 'primary';
if ($fields[$c->name]['type'] !== 'string') {
$fields[$c->name]['length'] = 11;
} }
} }
if ( }
$fields[$c['name']]['default'] == 'NULL' || if (
preg_match('/nextval\([\'"]?([\w.]+)/', $c['default'], $seq) $fields[$c->name]['default'] == 'NULL' ||
) { preg_match('/nextval\([\'"]?([\w.]+)/', $c->default, $seq)
$fields[$c['name']]['default'] = null; ) {
if (!empty($seq) && isset($seq[1])) { $fields[$c->name]['default'] = null;
$this->_sequenceMap[$table][$c['name']] = $seq[1]; if (!empty($seq) && isset($seq[1])) {
} $this->_sequenceMap[$table][$c->default] = $seq[1];
} }
} }
} }
@ -272,93 +249,11 @@ class DboPostgres extends DboSource {
if (isset($model->sequence)) { if (isset($model->sequence)) {
$this->_sequenceMap[$table][$model->primaryKey] = $model->sequence; $this->_sequenceMap[$table][$model->primaryKey] = $model->sequence;
} }
$cols->closeCursor();
return $fields; return $fields;
} }
/**
* Returns a quoted and escaped string of $data for use in an SQL statement.
*
* @param string $data String to be prepared for use in an SQL statement
* @param string $column The column into which this data will be inserted
* @param boolean $read Value to be used in READ or WRITE context
* @return string Quoted and escaped
* @todo Add logic that formats/escapes data based on column type
*/
function value($data, $column = null, $read = true) {
$parent = parent::value($data, $column);
if ($parent != null) {
return $parent;
}
if ($data === null || (is_array($data) && empty($data))) {
return 'NULL';
}
if (empty($column)) {
$column = $this->introspectType($data);
}
switch($column) {
case 'binary':
$data = pg_escape_bytea($data);
break;
case 'boolean':
if ($data === true || $data === 't' || $data === 'true') {
return 'TRUE';
} elseif ($data === false || $data === 'f' || $data === 'false') {
return 'FALSE';
}
return (!empty($data) ? 'TRUE' : 'FALSE');
break;
case 'float':
if (is_float($data)) {
$data = sprintf('%F', $data);
}
case 'inet':
case 'integer':
case 'date':
case 'datetime':
case 'timestamp':
case 'time':
if ($data === '') {
return $read ? 'NULL' : 'DEFAULT';
}
default:
$data = pg_escape_string($data);
break;
}
return "'" . $data . "'";
}
/**
* Returns a formatted error message from previous database operation.
*
* @return string Error message
*/
function lastError() {
$error = pg_last_error($this->connection);
return ($error) ? $error : 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() {
return ($this->_result) ? pg_affected_rows($this->_result) : false;
}
/**
* Returns number of rows in previous resultset. If no previous resultset exists,
* this returns false.
*
* @return integer Number of rows in resultset
*/
function lastNumRows() {
return ($this->_result) ? pg_num_rows($this->_result) : false;
}
/** /**
* Returns the ID generated from the previous INSERT operation. * Returns the ID generated from the previous INSERT operation.
* *
@ -368,8 +263,7 @@ class DboPostgres extends DboSource {
*/ */
function lastInsertId($source, $field = 'id') { function lastInsertId($source, $field = 'id') {
$seq = $this->getSequence($source, $field); $seq = $this->getSequence($source, $field);
$data = $this->fetchRow("SELECT currval('{$seq}') as max"); return $this->_connection->lastInsertId($seq);
return $data[0]['max'];
} }
/** /**
@ -394,20 +288,22 @@ class DboPostgres extends DboSource {
* Deletes all the records in a table and drops all associated auto-increment sequences * Deletes all the records in a table and drops all associated auto-increment sequences
* *
* @param mixed $table A string or model class representing the table to be truncated * @param mixed $table A string or model class representing the table to be truncated
* @param integer $reset If -1, sequences are dropped, if 0 (default), sequences are reset, * @param boolean $reset true for resseting the sequence, false to leave it as is.
* and if 1, sequences are not modified * and if 1, sequences are not modified
* @return boolean SQL TRUNCATE TABLE statement, false if not applicable. * @return boolean SQL TRUNCATE TABLE statement, false if not applicable.
*/ */
public function truncate($table, $reset = 0) { public function truncate($table, $reset = true) {
$table = $this->fullTableName($table, false);
if (!isset($this->_sequenceMap[$table])) {
$cache = $this->cacheSources;
$this->cacheSources = false;
$this->describe($table);
$this->cacheSources = $cache;
}
if (parent::truncate($table)) { if (parent::truncate($table)) {
$table = $this->fullTableName($table, false); if (isset($this->_sequenceMap[$table]) && $reset) {
if (isset($this->_sequenceMap[$table]) && $reset !== 1) {
foreach ($this->_sequenceMap[$table] as $field => $sequence) { foreach ($this->_sequenceMap[$table] as $field => $sequence) {
if ($reset === 0) { $this->_execute("ALTER SEQUENCE \"{$sequence}\" RESTART WITH 1");
$this->execute("ALTER SEQUENCE \"{$sequence}\" RESTART WITH 1");
} elseif ($reset === -1) {
$this->execute("DROP SEQUENCE IF EXISTS \"{$sequence}\"");
}
} }
} }
return true; return true;
@ -447,7 +343,7 @@ class DboPostgres extends DboSource {
} }
$count = count($fields); $count = count($fields);
if ($count >= 1 && strpos($fields[0], 'COUNT(*)') === false) { if ($count >= 1 && !preg_match('/^\s*COUNT\(\*/', $fields[0])) {
$result = array(); $result = array();
for ($i = 0; $i < $count; $i++) { for ($i = 0; $i < $count; $i++) {
if (!preg_match('/^.+\\(.*\\)/', $fields[$i]) && !preg_match('/\s+AS\s+/', $fields[$i])) { if (!preg_match('/^.+\\(.*\\)/', $fields[$i]) && !preg_match('/\s+AS\s+/', $fields[$i])) {
@ -781,20 +677,18 @@ class DboPostgres extends DboSource {
* @param unknown_type $results * @param unknown_type $results
*/ */
function resultSet(&$results) { function resultSet(&$results) {
$this->results =& $results;
$this->map = array(); $this->map = array();
$num_fields = pg_num_fields($results); $numFields = $results->columnCount();
$index = 0; $index = 0;
$j = 0; $j = 0;
while ($j < $num_fields) { while ($j < $numFields) {
$columnName = pg_field_name($results, $j); $column = $results->getColumnMeta($j);
if (strpos($column['name'], '__')) {
if (strpos($columnName, '__')) { list($table, $name) = explode('__', $column['name']);
$parts = explode('__', $columnName); $this->map[$index++] = array($table, $name, $column['native_type']);
$this->map[$index++] = array($parts[0], $parts[1]);
} else { } else {
$this->map[$index++] = array(0, $columnName); $this->map[$index++] = array(0, $column['name'], $column['native_type']);
} }
$j++; $j++;
} }
@ -806,12 +700,11 @@ class DboPostgres extends DboSource {
* @return unknown * @return unknown
*/ */
function fetchResult() { function fetchResult() {
if ($row = pg_fetch_row($this->results)) { if ($row = $this->_result->fetch()) {
$resultRow = array(); $resultRow = array();
foreach ($row as $index => $field) { foreach ($this->map as $index => $meta) {
list($table, $column) = $this->map[$index]; list($table, $column, $type) = $meta;
$type = pg_field_type($this->results, $index);
switch ($type) { switch ($type) {
case 'bool': case 'bool':
@ -819,7 +712,7 @@ class DboPostgres extends DboSource {
break; break;
case 'binary': case 'binary':
case 'bytea': case 'bytea':
$resultRow[$table][$column] = pg_unescape_bytea($row[$index]); $resultRow[$table][$column] = stream_get_contents($row[$index]);
break; break;
default: default:
$resultRow[$table][$column] = $row[$index]; $resultRow[$table][$column] = $row[$index];
@ -828,6 +721,7 @@ class DboPostgres extends DboSource {
} }
return $resultRow; return $resultRow;
} else { } else {
$this->_result->closeCursor();
return false; return false;
} }
} }
@ -836,23 +730,32 @@ class DboPostgres extends DboSource {
* Translates between PHP boolean values and PostgreSQL boolean values * Translates between PHP boolean values and PostgreSQL boolean values
* *
* @param mixed $data Value to be translated * @param mixed $data Value to be translated
* @param boolean $quote True to quote value, false otherwise * @param boolean $quote true to quote a boolean to be used in a query, flase to return the boolean value
* @return mixed Converted boolean value * @return boolean Converted boolean value
*/ */
function boolean($data, $quote = true) { function boolean($data, $quote = true) {
switch (true) { switch (true) {
case ($data === true || $data === false): case ($data === true || $data === false):
return $data; $result = $data;
break;
case ($data === 't' || $data === 'f'): case ($data === 't' || $data === 'f'):
return ($data === 't'); $result = ($data === 't');
break;
case ($data === 'true' || $data === 'false'): case ($data === 'true' || $data === 'false'):
return ($data === 'true'); $result = ($data === 'true');
break;
case ($data === 'TRUE' || $data === 'FALSE'): case ($data === 'TRUE' || $data === 'FALSE'):
return ($data === 'TRUE'); $result = ($data === 'TRUE');
break;
default: default:
return (bool)$data; $result = (bool) $data;
break; break;
} }
if ($quote) {
return ($result) ? 'TRUE' : 'FALSE';
}
return (int) $result;
} }
/** /**
@ -862,7 +765,10 @@ class DboPostgres extends DboSource {
* @return boolean True on success, false on failure * @return boolean True on success, false on failure
*/ */
function setEncoding($enc) { function setEncoding($enc) {
return pg_set_client_encoding($this->connection, $enc) == 0; if ($this->_execute('SET NAMES ?', array($enc))) {
return true;
}
return false;
} }
/** /**
@ -871,7 +777,7 @@ class DboPostgres extends DboSource {
* @return string The database encoding * @return string The database encoding
*/ */
function getEncoding() { function getEncoding() {
return pg_client_encoding($this->connection); $cosa = $this->_execute('SHOW client_encoding')->fetch();
} }
/** /**

View file

@ -19,11 +19,11 @@
*/ */
/** /**
* DBO implementation for the SQLite DBMS. * DBO implementation for the SQLite3 DBMS.
* *
* Long description for class * A DboSource adapter for SQLite 3 using PDO
* *
* @package cake * @package datasources
* @subpackage cake.cake.libs.model.datasources.dbo * @subpackage cake.cake.libs.model.datasources.dbo
*/ */
class DboSqlite extends DboSource { class DboSqlite extends DboSource {
@ -32,63 +32,48 @@ class DboSqlite extends DboSource {
* Datasource Description * Datasource Description
* *
* @var string * @var string
* @access public
*/ */
public $description = "SQLite DBO Driver"; var $description = "SQLite DBO Driver";
/** /**
* Opening quote for quoted identifiers * Quote Start
* *
* @var string * @var string
* @access public
*/ */
public $startQuote = '"'; var $startQuote = '"';
/** /**
* Closing quote for quoted identifiers * Quote End
* *
* @var string * @var string
* @access public
*/ */
public $endQuote = '"'; var $endQuote = '"';
/** /**
* Keeps the transaction statistics of CREATE/UPDATE/DELETE queries * Base configuration settings for SQLite3 driver
* *
* @var array * @var array
* @access protected * @access public
*/ */
protected $_queryStats = array(); var $_baseConfig = array(
'persistent' => false,
/**
* Base configuration settings for SQLite driver
*
* @var array
*/
protected $_baseConfig = array(
'persistent' => true,
'database' => null 'database' => null
); );
/** /**
* Index of basic SQL commands * SQLite3 column definition
* *
* @var array * @var array
* @access protected * @access public
*/ */
protected $_commands = array( var $columns = array(
'begin' => 'BEGIN TRANSACTION', 'primary_key' => array('name' => 'integer primary key autoincrement'),
'commit' => 'COMMIT TRANSACTION',
'rollback' => 'ROLLBACK TRANSACTION'
);
/**
* SQLite column definition
*
* @var array
*/
public $columns = array(
'primary_key' => array('name' => 'integer primary key'),
'string' => array('name' => 'varchar', 'limit' => '255'), 'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'), 'text' => array('name' => 'text'),
'integer' => array('name' => 'integer', 'limit' => 11, 'formatter' => 'intval'), 'integer' => array('name' => 'integer', 'limit' => null, 'formatter' => 'intval'),
'float' => array('name' => 'float', 'formatter' => 'floatval'), 'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
@ -104,7 +89,7 @@ class DboSqlite extends DboSource {
* @var array * @var array
* @access public * @access public
*/ */
public $fieldParameters = array( var $fieldParameters = array(
'collate' => array( 'collate' => array(
'value' => 'COLLATE', 'value' => 'COLLATE',
'quote' => false, 'quote' => false,
@ -122,83 +107,46 @@ class DboSqlite extends DboSource {
* *
* @param array $config Configuration array for connecting * @param array $config Configuration array for connecting
* @return mixed * @return mixed
* @access public
*/ */
function connect() { function connect() {
$config = $this->config; $config = $this->config;
if (!$config['persistent']) { $flags = array(PDO::ATTR_PERSISTENT => $config['persistent']);
$this->connection = sqlite_open($config['database']); try {
} else { $this->_connection = new PDO('sqlite:' . $config['database'], null, null, $flags);
$this->connection = sqlite_popen($config['database']); $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->connected = true;
} }
$this->connected = is_resource($this->connection); catch(PDOException $e) {
$this->errors[] = $e->getMessage();
if ($this->connected) {
$this->_execute('PRAGMA count_changes = 1;');
} }
return $this->connected; return $this->connected;
} }
/** /**
* Check that SQLite is enabled/installed * Check whether the MySQL extension is installed/loaded
* *
* @return boolean * @return boolean
*/ */
function enabled() { function enabled() {
return extension_loaded('sqlite'); return in_array('sqlite', PDO::getAvailableDrivers());
}
/**
* Disconnects from database.
*
* @return boolean True if the database could be disconnected, else false
*/
function disconnect() {
@sqlite_close($this->connection);
$this->connected = false;
return $this->connected;
}
/**
* Executes given SQL statement.
*
* @param string $sql SQL statement
* @return resource Result resource identifier
*/
function _execute($sql) {
$result = sqlite_query($this->connection, $sql);
if (preg_match('/^(INSERT|UPDATE|DELETE)/', $sql)) {
$this->resultSet($result);
list($this->_queryStats) = $this->fetchResult();
}
return $result;
}
/**
* Overrides DboSource::execute() to correctly handle query statistics
*
* @param string $sql
* @return unknown
*/
function execute($sql) {
$result = parent::execute($sql);
$this->_queryStats = array();
return $result;
} }
/** /**
* Returns an array of tables in the database. If there are no tables, an error is raised and the application exits. * Returns an array of tables in the database. If there are no tables, an error is raised and the application exits.
* *
* @return array Array of tablenames in the database * @return array Array of tablenames in the database
* @access public
*/ */
function listSources() { function listSources() {
$cache = parent::listSources(); $cache = parent::listSources();
if ($cache != null) { if ($cache != null) {
return $cache; return $cache;
} }
$result = $this->fetchAll("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;", false); $result = $this->fetchAll("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;", false);
if (empty($result)) { if (!$result || empty($result)) {
return array(); return array();
} else { } else {
$tables = array(); $tables = array();
@ -216,6 +164,7 @@ class DboSqlite extends DboSource {
* *
* @param string $tableName Name of database table to inspect * @param string $tableName Name of database table to inspect
* @return array Fields in table. Keys are name and type * @return array Fields in table. Keys are name and type
* @access public
*/ */
function describe(&$model) { function describe(&$model) {
$cache = parent::describe($model); $cache = parent::describe($model);
@ -223,65 +172,32 @@ class DboSqlite extends DboSource {
return $cache; return $cache;
} }
$fields = array(); $fields = array();
$result = $this->fetchAll('PRAGMA table_info(' . $this->fullTableName($model) . ')'); $result = $this->_execute('PRAGMA table_info(' . $model->tablePrefix . $model->table . ')');
foreach ($result as $column) { foreach ($result as $column) {
$fields[$column[0]['name']] = array( $column = (array) $column;
'type' => $this->column($column[0]['type']), $default = ($column['dflt_value'] === 'NULL') ? null : trim($column['dflt_value'], "'");
'null' => !$column[0]['notnull'],
'default' => $column[0]['dflt_value'], $fields[$column['name']] = array(
'length' => $this->length($column[0]['type']) 'type' => $this->column($column['type']),
'null' => !$column['notnull'],
'default' => $default,
'length' => $this->length($column['type'])
); );
if ($column[0]['pk'] == 1) { if ($column['pk'] == 1) {
$colLength = $this->length($column[0]['type']); $fields[$column['name']]['key'] = $this->index['PRI'];
$fields[$column[0]['name']] = array( $fields[$column['name']]['null'] = false;
'type' => $fields[$column[0]['name']]['type'], if (empty($fields[$column['name']]['length'])) {
'null' => false, $fields[$column['name']]['length'] = 11;
'default' => $column[0]['dflt_value'], }
'key' => $this->index['PRI'],
'length'=> ($colLength != null) ? $colLength : 11
);
} }
} }
$result->closeCursor();
$this->__cacheDescription($model->tablePrefix . $model->table, $fields); $this->__cacheDescription($model->tablePrefix . $model->table, $fields);
return $fields; return $fields;
} }
/**
* Returns a quoted and escaped string of $data for use in an SQL statement.
*
* @param string $data String to be prepared for use in an SQL statement
* @return string Quoted and escaped
*/
function value($data, $column = null, $safe = false) {
$parent = parent::value($data, $column, $safe);
if ($parent != null) {
return $parent;
}
if ($data === null) {
return 'NULL';
}
if ($data === '' && $column !== 'integer' && $column !== 'float' && $column !== 'boolean') {
return "''";
}
switch ($column) {
case 'boolean':
$data = $this->boolean((bool)$data);
break;
case 'integer':
case 'float':
if ($data === '') {
return 'NULL';
}
default:
$data = sqlite_escape_string($data);
break;
}
return "'" . $data . "'";
}
/** /**
* Generates and executes an SQL UPDATE statement for given model, fields, and values. * Generates and executes an SQL UPDATE statement for given model, fields, and values.
* *
@ -290,6 +206,7 @@ class DboSqlite extends DboSource {
* @param array $values * @param array $values
* @param mixed $conditions * @param mixed $conditions
* @return array * @return array
* @access public
*/ */
function update(&$model, $fields = array(), $values = null, $conditions = null) { function update(&$model, $fields = array(), $values = null, $conditions = null) {
if (empty($values) && !empty($fields)) { if (empty($values) && !empty($fields)) {
@ -302,8 +219,7 @@ class DboSqlite extends DboSource {
} }
} }
} }
$result = parent::update($model, $fields, $values, $conditions); return parent::update($model, $fields, $values, $conditions);
return $result;
} }
/** /**
@ -312,60 +228,11 @@ class DboSqlite extends DboSource {
* *
* @param mixed $table A string or model class representing the table to be truncated * @param mixed $table A string or model class representing the table to be truncated
* @return boolean SQL TRUNCATE TABLE statement, false if not applicable. * @return boolean SQL TRUNCATE TABLE statement, false if not applicable.
* @access public
*/ */
public function truncate($table) { function truncate($table) {
return $this->execute('DELETE From ' . $this->fullTableName($table)); $this->_execute('DELETE FROM sqlite_sequence where name=' . $this->fullTableName($table));
} return $this->execute('DELETE FROM ' . $this->fullTableName($table));
/**
* Returns a formatted error message from previous database operation.
*
* @return string Error message
*/
function lastError() {
$error = sqlite_last_error($this->connection);
if ($error) {
return $error.': '.sqlite_error_string($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 (!empty($this->_queryStats)) {
foreach (array('rows inserted', 'rows updated', 'rows deleted') as $key) {
if (array_key_exists($key, $this->_queryStats)) {
return $this->_queryStats[$key];
}
}
}
return false;
}
/**
* 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->hasResult()) {
sqlite_num_rows($this->_result);
}
return false;
}
/**
* Returns the ID generated from the previous INSERT operation.
*
* @return int
*/
function lastInsertId() {
return sqlite_last_insert_rowid($this->connection);
} }
/** /**
@ -373,6 +240,7 @@ class DboSqlite extends DboSource {
* *
* @param string $real Real database-layer column type (i.e. "varchar(255)") * @param string $real Real database-layer column type (i.e. "varchar(255)")
* @return string Abstract column type (i.e. "string") * @return string Abstract column type (i.e. "string")
* @access public
*/ */
function column($real) { function column($real) {
if (is_array($real)) { if (is_array($real)) {
@ -385,9 +253,7 @@ class DboSqlite extends DboSource {
$col = strtolower(str_replace(')', '', $real)); $col = strtolower(str_replace(')', '', $real));
$limit = null; $limit = null;
if (strpos($col, '(') !== false) { @list($col, $limit) = explode('(', $col);
list($col, $limit) = explode('(', $col);
}
if (in_array($col, array('text', 'integer', 'float', 'boolean', 'timestamp', 'date', 'datetime', 'time'))) { if (in_array($col, array('text', 'integer', 'float', 'boolean', 'timestamp', 'date', 'datetime', 'time'))) {
return $col; return $col;
@ -398,29 +264,55 @@ class DboSqlite extends DboSource {
if (in_array($col, array('blob', 'clob'))) { if (in_array($col, array('blob', 'clob'))) {
return 'binary'; return 'binary';
} }
if (strpos($col, 'numeric') !== false) { if (strpos($col, 'numeric') !== false || strpos($col, 'decimal') !== false) {
return 'float'; return 'float';
} }
return 'text'; return 'text';
} }
/** /**
* Enter description here... * Generate ResultSet
* *
* @param unknown_type $results * @param mixed $results
* @access public
*/ */
function resultSet(&$results) { function resultSet($results) {
$this->results =& $results; $this->results = $results;
$this->map = array(); $this->map = array();
$fieldCount = sqlite_num_fields($results); $num_fields = $results->columnCount();
$index = $j = 0; $index = 0;
$j = 0;
while ($j < $fieldCount) { //PDO::getColumnMeta is experimental and does not work with sqlite3,
$columnName = str_replace('"', '', sqlite_field_name($results, $j)); // so try to figure it out based on the querystring
$querystring = $results->queryString;
if (stripos($querystring, 'SELECT') === 0) {
$last = stripos($querystring, 'FROM');
if ($last !== false) {
$selectpart = substr($querystring, 7, $last - 8);
$selects = explode(',', $selectpart);
}
} elseif (strpos($querystring, 'PRAGMA table_info') === 0) {
$selects = array('cid', 'name', 'type', 'notnull', 'dflt_value', 'pk');
} elseif(strpos($querystring, 'PRAGMA index_list') === 0) {
$selects = array('seq', 'name', 'unique');
} elseif(strpos($querystring, 'PRAGMA index_info') === 0) {
$selects = array('seqno', 'cid', 'name');
}
while ($j < $num_fields) {
if (preg_match('/\bAS\s+(.*)/i', $selects[$j], $matches)) {
$columnName = trim($matches[1],'"');
} else {
$columnName = trim(str_replace('"', '', $selects[$j]));
}
if (strpos($selects[$j], 'DISTINCT') === 0) {
$columnName = str_ireplace('DISTINCT', '', $columnName);
}
if (strpos($columnName, '.')) { if (strpos($columnName, '.')) {
$parts = explode('.', $columnName); $parts = explode('.', $columnName);
$this->map[$index++] = array($parts[0], $parts[1]); $this->map[$index++] = array(trim($parts[0]), trim($parts[1]));
} else { } else {
$this->map[$index++] = array(0, $columnName); $this->map[$index++] = array(0, $columnName);
} }
@ -431,34 +323,30 @@ class DboSqlite extends DboSource {
/** /**
* Fetches the next row from the current result set * Fetches the next row from the current result set
* *
* @return unknown * @return mixed array with results fetched and mapped to column names or false if there is no results left to fetch
*/ */
function fetchResult() { function fetchResult() {
if ($row = sqlite_fetch_array($this->results, SQLITE_ASSOC)) { if ($row = $this->_result->fetch()) {
$resultRow = array(); $resultRow = array();
$i = 0; foreach ($this->map as $col => $meta) {
list($table, $column) = $meta;
foreach ($row as $index => $field) { $resultRow[$table][$column] = $row[$col];
if (strpos($index, '.')) {
list($table, $column) = explode('.', str_replace('"', '', $index));
$resultRow[$table][$column] = $row[$index];
} else {
$resultRow[0][str_replace('"', '', $index)] = $row[$index];
}
$i++;
} }
return $resultRow; return $resultRow;
} else { } else {
$this->_result->closeCursor();
return false; return false;
} }
} }
/** /**
* Returns a limit statement in the correct format for the particular database. * Returns a limit statement in the correct format for the particular database.
* *
* @param integer $limit Limit of results returned * @param integer $limit Limit of results returned
* @param integer $offset Offset from which to start results * @param integer $offset Offset from which to start results
* @return string SQL limit/offset statement * @return string SQL limit/offset statement
* @access public
*/ */
function limit($limit, $offset = null) { function limit($limit, $offset = null) {
if ($limit) { if ($limit) {
@ -479,8 +367,9 @@ class DboSqlite extends DboSource {
* Generate a database-native column schema string * Generate a database-native column schema string
* *
* @param array $column An array structured like the following: array('name'=>'value', 'type'=>'value'[, options]), * @param array $column An array structured like the following: array('name'=>'value', 'type'=>'value'[, options]),
* where options can be 'default', 'length', or 'key'. * where options can be 'default', 'length', or 'key'.
* @return string * @return string
* @access public
*/ */
function buildColumn($column) { function buildColumn($column) {
$name = $type = null; $name = $type = null;
@ -488,12 +377,12 @@ class DboSqlite extends DboSource {
extract($column); extract($column);
if (empty($name) || empty($type)) { if (empty($name) || empty($type)) {
trigger_error(__('Column name or type not defined in schema'), E_USER_WARNING); trigger_error('Column name or type not defined in schema', E_USER_WARNING);
return null; return null;
} }
if (!isset($this->columns[$type])) { if (!isset($this->columns[$type])) {
trigger_error(sprintf(__('Column type %s does not exist'), $type), E_USER_WARNING); trigger_error("Column type {$type} does not exist", E_USER_WARNING);
return null; return null;
} }
@ -509,6 +398,7 @@ class DboSqlite extends DboSource {
* Sets the database encoding * Sets the database encoding
* *
* @param string $enc Database encoding * @param string $enc Database encoding
* @access public
*/ */
function setEncoding($enc) { function setEncoding($enc) {
if (!in_array($enc, array("UTF-8", "UTF-16", "UTF-16le", "UTF-16be"))) { if (!in_array($enc, array("UTF-8", "UTF-16", "UTF-16le", "UTF-16be"))) {
@ -521,6 +411,7 @@ class DboSqlite extends DboSource {
* Gets the database encoding * Gets the database encoding
* *
* @return string The database encoding * @return string The database encoding
* @access public
*/ */
function getEncoding() { function getEncoding() {
return $this->fetchRow('PRAGMA encoding'); return $this->fetchRow('PRAGMA encoding');
@ -532,6 +423,7 @@ class DboSqlite extends DboSource {
* @param array $indexes * @param array $indexes
* @param string $table * @param string $table
* @return string * @return string
* @access public
*/ */
function buildIndex($indexes, $table = null) { function buildIndex($indexes, $table = null) {
$join = array(); $join = array();
@ -547,11 +439,12 @@ class DboSqlite extends DboSource {
$out .= 'UNIQUE '; $out .= 'UNIQUE ';
} }
if (is_array($value['column'])) { if (is_array($value['column'])) {
$value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column'])); $value['column'] = join(', ', array_map(array(&$this, 'name'), $value['column']));
} else { } else {
$value['column'] = $this->name($value['column']); $value['column'] = $this->name($value['column']);
} }
$out .= "INDEX {$name} ON {$table}({$value['column']});"; $t = trim($table, '"');
$out .= "INDEX {$t}_{$name} ON {$table}({$value['column']});";
$join[] = $out; $join[] = $out;
} }
return $join; return $join;
@ -563,13 +456,17 @@ class DboSqlite extends DboSource {
* *
* @param string $model Name of model to inspect * @param string $model Name of model to inspect
* @return array Fields in table. Keys are column and unique * @return array Fields in table. Keys are column and unique
* @access public
*/ */
function index(&$model) { function index(&$model) {
$index = array(); $index = array();
$table = $this->fullTableName($model); $table = $this->fullTableName($model);
if ($table) { if ($table) {
$indexes = $this->query('PRAGMA index_list(' . $table . ')'); $indexes = $this->query('PRAGMA index_list(' . $table . ')');
$tableInfo = $this->query('PRAGMA table_info(' . $table . ')');
if (is_bool($indexes)) {
return array();
}
foreach ($indexes as $i => $info) { foreach ($indexes as $i => $info) {
$key = array_pop($info); $key = array_pop($info);
$keyInfo = $this->query('PRAGMA index_info("' . $key['name'] . '")'); $keyInfo = $this->query('PRAGMA index_info("' . $key['name'] . '")');
@ -600,16 +497,17 @@ class DboSqlite extends DboSource {
* @param string $type * @param string $type
* @param array $data * @param array $data
* @return string * @return string
* @access public
*/ */
function renderStatement($type, $data) { function renderStatement($type, $data) {
switch (strtolower($type)) { switch (strtolower($type)) {
case 'schema': case 'schema':
extract($data); extract($data);
if (is_array($columns)) {
foreach (array('columns', 'indexes') as $var) { $columns = "\t" . join(",\n\t", array_filter($columns));
if (is_array(${$var})) { }
${$var} = "\t" . implode(",\n\t", array_filter(${$var})); if (is_array($indexes)) {
} $indexes = "\t" . join("\n\t", array_filter($indexes));
} }
return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}"; return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
break; break;
@ -618,4 +516,32 @@ class DboSqlite extends DboSource {
break; break;
} }
} }
/**
* PDO deals in objects, not resources, so overload accordingly.
*
* @return boolean
* @access public
*/
function hasResult() {
return is_object($this->_result);
}
/**
* Generate a "drop table" statement for the given Schema object
*
* @param object $schema An instance of a subclass of CakeSchema
* @param string $table Optional. If specified only the table name given will be generated.
* Otherwise, all tables defined in the schema are generated.
* @return string
*/
public function dropSchema(CakeSchema $schema, $table = null) {
$out = '';
foreach ($schema->tables as $curTable => $columns) {
if (!$table || $table == $curTable) {
$out .= 'DROP TABLE IF EXISTS ' . $this->fullTableName($curTable) . ";\n";
}
}
return $out;
}
} }

View file

@ -44,8 +44,6 @@ class AclShellTest extends CakeTestCase {
* @return void * @return void
*/ */
public function setUp() { public function setUp() {
parent::setUp();
Configure::write('Acl.database', 'test'); Configure::write('Acl.database', 'test');
Configure::write('Acl.classname', 'DbAcl'); Configure::write('Acl.classname', 'DbAcl');
@ -59,7 +57,6 @@ class AclShellTest extends CakeTestCase {
); );
$collection = new ComponentCollection(); $collection = new ComponentCollection();
$this->Task->Acl = new AclComponent($collection); $this->Task->Acl = new AclComponent($collection);
$this->Task->params['datasource'] = 'test'; $this->Task->params['datasource'] = 'test';
} }
@ -206,8 +203,9 @@ class AclShellTest extends CakeTestCase {
$this->Task->expects($this->at(0))->method('out') $this->Task->expects($this->at(0))->method('out')
->with($this->matchesRegularExpression('/granted/'), true); ->with($this->matchesRegularExpression('/granted/'), true);
$this->Task->grant(); $this->Task->grant();
$node = $this->Task->Acl->Aro->node(array('model' => 'AuthUser', 'foreign_key' => 2));
$node = $this->Task->Acl->Aro->read(null, $node[0]['Aro']['id']);
$node = $this->Task->Acl->Aro->read(null, 4);
$this->assertFalse(empty($node['Aco'][0])); $this->assertFalse(empty($node['Aco'][0]));
$this->assertEqual($node['Aco'][0]['Permission']['_create'], 1); $this->assertEqual($node['Aco'][0]['Permission']['_create'], 1);
} }
@ -224,7 +222,8 @@ class AclShellTest extends CakeTestCase {
$this->Task->deny(); $this->Task->deny();
$node = $this->Task->Acl->Aro->read(null, 4); $node = $this->Task->Acl->Aro->node(array('model' => 'AuthUser', 'foreign_key' => 2));
$node = $this->Task->Acl->Aro->read(null, $node[0]['Aro']['id']);
$this->assertFalse(empty($node['Aco'][0])); $this->assertFalse(empty($node['Aco'][0]));
$this->assertEqual($node['Aco'][0]['Permission']['_create'], -1); $this->assertEqual($node['Aco'][0]['Permission']['_create'], -1);
} }
@ -274,7 +273,8 @@ class AclShellTest extends CakeTestCase {
$this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'all'); $this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'all');
$this->Task->inherit(); $this->Task->inherit();
$node = $this->Task->Acl->Aro->read(null, 4); $node = $this->Task->Acl->Aro->node(array('model' => 'AuthUser', 'foreign_key' => 2));
$node = $this->Task->Acl->Aro->read(null, $node[0]['Aro']['id']);
$this->assertFalse(empty($node['Aco'][0])); $this->assertFalse(empty($node['Aco'][0]));
$this->assertEqual($node['Aco'][0]['Permission']['_create'], 0); $this->assertEqual($node['Aco'][0]['Permission']['_create'], 0);
} }
@ -286,9 +286,13 @@ class AclShellTest extends CakeTestCase {
*/ */
public function testGetPath() { public function testGetPath() {
$this->Task->args = array('aro', 'AuthUser.2'); $this->Task->args = array('aro', 'AuthUser.2');
$this->Task->expects($this->at(2))->method('out')->with('[1] ROOT'); $node = $this->Task->Acl->Aro->node(array('model' => 'AuthUser', 'foreign_key' => 2));
$this->Task->expects($this->at(3))->method('out')->with(' [2] admins'); $first = $node[0]['Aro']['id'];
$this->Task->expects($this->at(4))->method('out')->with(' [4] Elrond'); $second = $node[1]['Aro']['id'];
$last = $node[2]['Aro']['id'];
$this->Task->expects($this->at(2))->method('out')->with('['.$last.'] ROOT');
$this->Task->expects($this->at(3))->method('out')->with(' ['.$second.'] admins');
$this->Task->expects($this->at(4))->method('out')->with(' ['.$first.'] Elrond');
$this->Task->getPath(); $this->Task->getPath();
} }

View file

@ -96,7 +96,7 @@ class BakeShellTest extends CakeTestCase {
$this->Shell->expects($this->at(1))->method('out')->with('Bake All'); $this->Shell->expects($this->at(1))->method('out')->with('Bake All');
$this->Shell->expects($this->at(3))->method('out')->with('User Model was baked.'); $this->Shell->expects($this->at(3))->method('out')->with('User Model was baked.');
$this->Shell->expects($this->at(5))->method('out')->with('User Controller was baked.'); $this->Shell->expects($this->at(5))->method('out')->with('<success>Bake All complete</success>');
$this->Shell->expects($this->at(7))->method('out')->with('User Views were baked.'); $this->Shell->expects($this->at(7))->method('out')->with('User Views were baked.');
$this->Shell->expects($this->at(8))->method('out')->with('Bake All complete'); $this->Shell->expects($this->at(8))->method('out')->with('Bake All complete');

View file

@ -223,7 +223,7 @@ class SchemaShellTest extends CakeTestCase {
$this->file = new File(TMP . 'tests' . DS . 'i18n.sql'); $this->file = new File(TMP . 'tests' . DS . 'i18n.sql');
$contents = $this->file->read(); $contents = $this->file->read();
$this->assertPattern('/DROP TABLE/', $contents); $this->assertPattern('/DROP TABLE/', $contents);
$this->assertPattern('/CREATE TABLE `i18n`/', $contents); $this->assertPattern('/CREATE TABLE.*?i18n/', $contents);
$this->assertPattern('/id/', $contents); $this->assertPattern('/id/', $contents);
$this->assertPattern('/model/', $contents); $this->assertPattern('/model/', $contents);
$this->assertPattern('/field/', $contents); $this->assertPattern('/field/', $contents);
@ -253,7 +253,7 @@ class SchemaShellTest extends CakeTestCase {
$this->file = new File(TMP . 'tests' . DS . 'dump_test.sql'); $this->file = new File(TMP . 'tests' . DS . 'dump_test.sql');
$contents = $this->file->read(); $contents = $this->file->read();
$this->assertPattern('/CREATE TABLE `test_plugin_acos`/', $contents); $this->assertPattern('/CREATE TABLE.*?test_plugin_acos/', $contents);
$this->assertPattern('/id/', $contents); $this->assertPattern('/id/', $contents);
$this->assertPattern('/model/', $contents); $this->assertPattern('/model/', $contents);
@ -339,6 +339,7 @@ class SchemaShellTest extends CakeTestCase {
), true); ), true);
App::objects('plugin', null, false); App::objects('plugin', null, false);
$this->db->cacheSources = false;
$this->Shell->params = array( $this->Shell->params = array(
'plugin' => 'TestPlugin', 'plugin' => 'TestPlugin',
'connection' => 'test' 'connection' => 'test'
@ -366,8 +367,7 @@ class SchemaShellTest extends CakeTestCase {
*/ */
public function testCreateNoArgs() { public function testCreateNoArgs() {
$this->Shell->params = array( $this->Shell->params = array(
'connection' => 'test', 'connection' => 'test'
'path' => APP . 'config' . DS . 'sql'
); );
$this->Shell->args = array('i18n'); $this->Shell->args = array('i18n');
$this->Shell->startup(); $this->Shell->startup();
@ -375,6 +375,8 @@ class SchemaShellTest extends CakeTestCase {
$this->Shell->create(); $this->Shell->create();
$db = ConnectionManager::getDataSource('test'); $db = ConnectionManager::getDataSource('test');
$db->cacheSources = false;
$sources = $db->listSources(); $sources = $db->listSources();
$this->assertTrue(in_array($db->config['prefix'] . 'i18n', $sources)); $this->assertTrue(in_array($db->config['prefix'] . 'i18n', $sources));
@ -396,7 +398,7 @@ class SchemaShellTest extends CakeTestCase {
$this->Shell->params = array( $this->Shell->params = array(
'connection' => 'test', 'connection' => 'test',
'name' => 'DbAcl', 'name' => 'DbAcl',
'path' => APP . 'config' . DS . 'schema' 'path' => CONFIGS . 'schema'
); );
$this->Shell->args = array('DbAcl', 'acos'); $this->Shell->args = array('DbAcl', 'acos');
$this->Shell->startup(); $this->Shell->startup();
@ -404,6 +406,7 @@ class SchemaShellTest extends CakeTestCase {
$this->Shell->create(); $this->Shell->create();
$db = ConnectionManager::getDataSource('test'); $db = ConnectionManager::getDataSource('test');
$db->cacheSources = false;
$sources = $db->listSources(); $sources = $db->listSources();
$this->assertTrue(in_array($db->config['prefix'] . 'acos', $sources), 'acos should be present.'); $this->assertTrue(in_array($db->config['prefix'] . 'acos', $sources), 'acos should be present.');
$this->assertFalse(in_array($db->config['prefix'] . 'aros', $sources), 'aros should not be found.'); $this->assertFalse(in_array($db->config['prefix'] . 'aros', $sources), 'aros should not be found.');

View file

@ -37,8 +37,15 @@ class AllDatabaseTest extends PHPUnit_Framework_TestSuite {
$suite = new PHPUnit_Framework_TestSuite('Datasources, Schema and DbAcl tests'); $suite = new PHPUnit_Framework_TestSuite('Datasources, Schema and DbAcl tests');
$path = CORE_TEST_CASES . DS . 'libs' . DS . 'model' . DS; $path = CORE_TEST_CASES . DS . 'libs' . DS . 'model' . DS;
$tasks = array(
$tasks = array('db_acl', 'cake_schema', 'connection_manager', 'datasources' . DS . 'dbo_source'); 'db_acl',
'cake_schema',
'connection_manager',
'datasources' . DS . 'dbo_source',
'datasources' . DS . 'dbo' . DS . 'dbo_mysql',
'datasources' . DS . 'dbo' . DS . 'dbo_postgres',
'datasources' . DS . 'dbo' . DS . 'dbo_sqlite'
);
foreach ($tasks as $task) { foreach ($tasks as $task) {
$suite->addTestFile($path . $task . '.test.php'); $suite->addTestFile($path . $task . '.test.php');
} }

View file

@ -546,6 +546,7 @@ class BehaviorCollectionTest extends CakeTestCase {
*/ */
function testBehaviorToggling() { function testBehaviorToggling() {
$Apple = new Apple(); $Apple = new Apple();
$expected = $Apple->find('all');
$this->assertIdentical($Apple->Behaviors->enabled(), array()); $this->assertIdentical($Apple->Behaviors->enabled(), array());
$Apple->Behaviors->init('Apple', array('Test' => array('key' => 'value'))); $Apple->Behaviors->init('Apple', array('Test' => array('key' => 'value')));

View file

@ -185,6 +185,7 @@ class TranslateBehaviorTest extends CakeTestCase {
$TestModel = new TranslatedItem(); $TestModel = new TranslatedItem();
$TestModel->locale = 'eng'; $TestModel->locale = 'eng';
$result = $TestModel->read(null, 1); $result = $TestModel->read(null, 1);
$expected = array( $expected = array(
'TranslatedItem' => array( 'TranslatedItem' => array(
@ -313,17 +314,17 @@ class TranslateBehaviorTest extends CakeTestCase {
$result = $TestModel->find('all', array('fields' => array('TranslatedItem.title'))); $result = $TestModel->find('all', array('fields' => array('TranslatedItem.title')));
$expected = array( $expected = array(
array( array(
'TranslatedItem' => array('id' => 1, 'locale' => 'eng', 'title' => 'Title #1'), 'TranslatedItem' => array('id' => 1, 'locale' => 'eng', 'title' => 'Title #1', 'slug' => 'first_translated'),
'Title' => array(array('foreign_key' => 1, 'content' => 'Title #1')), 'Title' => array(array('foreign_key' => 1, 'content' => 'Title #1')),
'Content' => array(array('foreign_key' => 1, 'content' => 'Content #1')) 'Content' => array(array('foreign_key' => 1, 'content' => 'Content #1'))
), ),
array( array(
'TranslatedItem' => array('id' => 2, 'locale' => 'eng', 'title' => 'Title #2'), 'TranslatedItem' => array('id' => 2, 'locale' => 'eng', 'title' => 'Title #2', 'slug' => 'second_translated'),
'Title' => array(array('foreign_key' => 2, 'content' => 'Title #2')), 'Title' => array(array('foreign_key' => 2, 'content' => 'Title #2')),
'Content' => array(array('foreign_key' => 2, 'content' => 'Content #2')) 'Content' => array(array('foreign_key' => 2, 'content' => 'Content #2'))
), ),
array( array(
'TranslatedItem' => array('id' => 3, 'locale' => 'eng', 'title' => 'Title #3'), 'TranslatedItem' => array('id' => 3, 'locale' => 'eng', 'title' => 'Title #3','slug' => 'third_translated'),
'Title' => array(array('foreign_key' => 3, 'content' => 'Title #3')), 'Title' => array(array('foreign_key' => 3, 'content' => 'Title #3')),
'Content' => array(array('foreign_key' => 3, 'content' => 'Content #3')) 'Content' => array(array('foreign_key' => 3, 'content' => 'Content #3'))
) )
@ -342,16 +343,7 @@ class TranslateBehaviorTest extends CakeTestCase {
$TestModel = new TranslatedItem(); $TestModel = new TranslatedItem();
$TestModel->locale = array('deu', 'eng', 'cze'); $TestModel->locale = array('deu', 'eng', 'cze');
$delete = array(
array('locale' => 'deu'),
array('foreign_key' => 1, 'field' => 'title', 'locale' => 'eng'),
array('foreign_key' => 1, 'field' => 'content', 'locale' => 'cze'),
array('foreign_key' => 2, 'field' => 'title', 'locale' => 'cze'),
array('foreign_key' => 2, 'field' => 'content', 'locale' => 'eng'),
array('foreign_key' => 3, 'field' => 'title')
);
$I18nModel = ClassRegistry::getObject('TranslateTestModel');
$I18nModel->deleteAll(array('or' => $delete));
$result = $TestModel->read(null, 1); $result = $TestModel->read(null, 1);
$expected = array( $expected = array(
@ -359,8 +351,8 @@ class TranslateBehaviorTest extends CakeTestCase {
'id' => 1, 'id' => 1,
'slug' => 'first_translated', 'slug' => 'first_translated',
'locale' => 'deu', 'locale' => 'deu',
'title' => 'Titulek #1', 'title' => 'Titel #1',
'content' => 'Content #1' 'content' => 'Inhalt #1'
) )
); );
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
@ -371,28 +363,29 @@ class TranslateBehaviorTest extends CakeTestCase {
'TranslatedItem' => array( 'TranslatedItem' => array(
'slug' => 'first_translated', 'slug' => 'first_translated',
'locale' => 'deu', 'locale' => 'deu',
'title' => 'Titulek #1', 'content' => 'Inhalt #1',
'content' => 'Content #1' 'title' => 'Titel #1'
) )
), ),
array( array(
'TranslatedItem' => array( 'TranslatedItem' => array(
'slug' => 'second_translated', 'slug' => 'second_translated',
'locale' => 'deu', 'locale' => 'deu',
'title' => 'Title #2', 'title' => 'Titel #2',
'content' => 'Obsah #2' 'content' => 'Inhalt #2'
) )
), ),
array( array(
'TranslatedItem' => array( 'TranslatedItem' => array(
'slug' => 'third_translated', 'slug' => 'third_translated',
'locale' => 'deu', 'locale' => 'deu',
'title' => '', 'title' => 'Titel #3',
'content' => 'Content #3' 'content' => 'Inhalt #3'
) )
) )
); );
$this->assertEqual($result, $expected);
$this->assertEquals($result, $expected);
} }
/** /**
@ -640,6 +633,8 @@ class TranslateBehaviorTest extends CakeTestCase {
$translations = array('title' => 'Title', 'content' => 'Content'); $translations = array('title' => 'Title', 'content' => 'Content');
$TestModel->bindTranslation($translations, false); $TestModel->bindTranslation($translations, false);
$result = $TestModel->read(null, 1); $result = $TestModel->read(null, 1);
$result['Title'] = Set::sort($result['Title'], '{n}.id', 'asc');
$result['Content'] = Set::sort($result['Content'], '{n}.id', 'asc');
$expected = array( $expected = array(
'TranslatedItem' => array('id' => 1, 'slug' => 'first_translated', 'locale' => 'cze', 'title' => 'Titulek #1', 'content' => 'Upraveny obsah #1'), 'TranslatedItem' => array('id' => 1, 'slug' => 'first_translated', 'locale' => 'cze', 'title' => 'Titulek #1', 'content' => 'Upraveny obsah #1'),
'Title' => array( 'Title' => array(

View file

@ -1431,7 +1431,6 @@ class ScopedTreeTest extends CakeTestCase {
function testTranslatingTree() { function testTranslatingTree() {
$this->Tree = new FlagTree(); $this->Tree = new FlagTree();
$this->Tree->cacheQueries = false; $this->Tree->cacheQueries = false;
$this->Tree->translateModel = 'TranslateTreeTestModel';
$this->Tree->Behaviors->attach('Translate', array('name')); $this->Tree->Behaviors->attach('Translate', array('name'));
//Save //Save

View file

@ -210,7 +210,7 @@ class TestAppSchema extends CakeSchema {
*/ */
public $datatypes = array( public $datatypes = array(
'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'), 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
'float_field' => array('type' => 'float', 'null' => false, 'length' => '5,2', 'default' => ''), 'float_field' => array('type' => 'float', 'null' => false, 'length' => '5,2', 'default' => '', 'collate' => null, 'comment' => null),
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)), 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
'tableParameters' => array() 'tableParameters' => array()
); );
@ -523,6 +523,7 @@ class CakeSchemaTest extends CakeTestCase {
*/ */
function setUp() { function setUp() {
parent::setUp(); parent::setUp();
ConnectionManager::getDataSource('test')->cacheSources = false;
$this->Schema = new TestAppSchema(); $this->Schema = new TestAppSchema();
} }
@ -577,18 +578,28 @@ class CakeSchemaTest extends CakeTestCase {
} }
$this->assertEqual( $this->assertEqual(
$read['tables']['datatypes']['float_field'], $read['tables']['datatypes']['float_field']['length'],
$this->Schema->tables['datatypes']['float_field'] $this->Schema->tables['datatypes']['float_field']['length']
); );
$db =& ConnectionManager::getDataSource('test'); $this->assertEqual(
$read['tables']['datatypes']['float_field']['type'],
$this->Schema->tables['datatypes']['float_field']['type']
);
$this->assertEqual(
$read['tables']['datatypes']['float_field']['null'],
$this->Schema->tables['datatypes']['float_field']['null']
);
$db = ConnectionManager::getDataSource('test');
$config = $db->config; $config = $db->config;
$config['prefix'] = 'schema_test_prefix_'; $config['prefix'] = 'schema_test_prefix_';
ConnectionManager::create('schema_prefix', $config); ConnectionManager::create('schema_prefix', $config);
$read = $this->Schema->read(array('connection' => 'schema_prefix', 'models' => false)); $read = $this->Schema->read(array('connection' => 'schema_prefix', 'models' => false));
$this->assertTrue(empty($read['tables'])); $this->assertTrue(empty($read['tables']));
$SchemaPost =& ClassRegistry::init('SchemaPost'); $SchemaPost = ClassRegistry::init('SchemaPost');
$SchemaPost->table = 'sts'; $SchemaPost->table = 'sts';
$SchemaPost->tablePrefix = 'po'; $SchemaPost->tablePrefix = 'po';
$read = $this->Schema->read(array( $read = $this->Schema->read(array(
@ -612,7 +623,7 @@ class CakeSchemaTest extends CakeTestCase {
* @return void * @return void
*/ */
function testSchemaReadWithTablePrefix() { function testSchemaReadWithTablePrefix() {
$model =& new SchemaPrefixAuthUser(); $model = new SchemaPrefixAuthUser();
$Schema = new CakeSchema(); $Schema = new CakeSchema();
$read = $Schema->read(array( $read = $Schema->read(array(
@ -684,7 +695,7 @@ class CakeSchemaTest extends CakeTestCase {
return; return;
} }
$db2 =& ConnectionManager::getDataSource('test2'); $db2 = ConnectionManager::getDataSource('test2');
$fixture = new SchemaCrossDatabaseFixture(); $fixture = new SchemaCrossDatabaseFixture();
$fixture->create($db2); $fixture->create($db2);
$fixture->insert($db2); $fixture->insert($db2);
@ -953,7 +964,7 @@ class CakeSchemaTest extends CakeTestCase {
* @return void * @return void
*/ */
function testSchemaLoading() { function testSchemaLoading() {
$Other =& $this->Schema->load(array('name' => 'MyOtherApp', 'path' => TMP . 'tests')); $Other = $this->Schema->load(array('name' => 'MyOtherApp', 'path' => TMP . 'tests'));
$this->assertEqual($Other->name, 'MyOtherApp'); $this->assertEqual($Other->name, 'MyOtherApp');
$this->assertEqual($Other->tables, $this->Schema->tables); $this->assertEqual($Other->tables, $this->Schema->tables);
} }
@ -967,7 +978,7 @@ class CakeSchemaTest extends CakeTestCase {
App::build(array( App::build(array(
'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS) 'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS)
)); ));
$Other =& $this->Schema->load(array('name' => 'TestPluginApp', 'plugin' => 'TestPlugin')); $Other = $this->Schema->load(array('name' => 'TestPluginApp', 'plugin' => 'TestPlugin'));
$this->assertEqual($Other->name, 'TestPluginApp'); $this->assertEqual($Other->name, 'TestPluginApp');
$this->assertEqual(array_keys($Other->tables), array('test_plugin_acos')); $this->assertEqual(array_keys($Other->tables), array('test_plugin_acos'));
@ -981,7 +992,7 @@ class CakeSchemaTest extends CakeTestCase {
* @return void * @return void
*/ */
function testSchemaCreateTable() { function testSchemaCreateTable() {
$db =& ConnectionManager::getDataSource('test'); $db = ConnectionManager::getDataSource('test');
$db->cacheSources = false; $db->cacheSources = false;
$Schema = new CakeSchema(array( $Schema = new CakeSchema(array(

View file

@ -226,7 +226,6 @@ class ConnectionManagerTest extends CakeTestCase {
function testLoadDataSource() { function testLoadDataSource() {
$connections = array( $connections = array(
array('classname' => 'DboMysql', 'filename' => 'dbo' . DS . 'dbo_mysql'), array('classname' => 'DboMysql', 'filename' => 'dbo' . DS . 'dbo_mysql'),
array('classname' => 'DboMysqli', 'filename' => 'dbo' . DS . 'dbo_mysqli'),
array('classname' => 'DboMssql', 'filename' => 'dbo' . DS . 'dbo_mssql'), array('classname' => 'DboMssql', 'filename' => 'dbo' . DS . 'dbo_mssql'),
array('classname' => 'DboOracle', 'filename' => 'dbo' . DS . 'dbo_oracle'), array('classname' => 'DboOracle', 'filename' => 'dbo' . DS . 'dbo_oracle'),
); );

File diff suppressed because it is too large Load diff

View file

@ -1,328 +0,0 @@
<?php
/**
* DboMysqliTest file
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.libs
* @since CakePHP(tm) v 1.2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Core', array('Model', 'DataSource', 'DboSource', 'DboMysqli'));
/**
* DboMysqliTestDb class
*
* @package cake
* @subpackage cake.tests.cases.libs.model.datasources
*/
class DboMysqliTestDb extends DboMysqli {
/**
* simulated property
*
* @var array
* @access public
*/
public $simulated = array();
/**
* testing property
*
* @var bool true
* @access public
*/
public $testing = true;
/**
* execute method
*
* @param mixed $sql
* @access protected
* @return void
*/
function _execute($sql) {
if ($this->testing) {
$this->simulated[] = $sql;
return null;
}
return parent::_execute($sql);
}
/**
* getLastQuery method
*
* @access public
* @return void
*/
function getLastQuery() {
return $this->simulated[count($this->simulated) - 1];
}
}
/**
* MysqliTestModel class
*
* @package cake
* @subpackage cake.tests.cases.libs.model.datasources
*/
class MysqliTestModel extends Model {
/**
* name property
*
* @var string 'MysqlTestModel'
* @access public
*/
public $name = 'MysqliTestModel';
/**
* useTable property
*
* @var bool false
* @access public
*/
public $useTable = false;
/**
* schema method
*
* @access public
* @return void
*/
function schema() {
return array(
'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
'client_id' => array('type' => 'integer', 'null' => '', 'default' => '0', 'length' => '11'),
'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
'login' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
'passwd' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '255'),
'addr_1' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '255'),
'addr_2' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '25'),
'zip_code' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
'city' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
'country' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
'phone' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
'fax' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
'url' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '255'),
'email' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
'comments' => array('type' => 'text', 'null' => '1', 'default' => '', 'length' => ''),
'last_login'=> array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => ''),
'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
);
}
}
/**
* DboMysqliTest class
*
* @package cake
* @subpackage cake.tests.cases.libs.model.datasources.dbo
*/
class DboMysqliTest extends CakeTestCase {
public $fixtures = array('core.datatype');
/**
* The Dbo instance to be tested
*
* @var DboSource
* @access public
*/
public $Dbo = null;
/**
* Sets up a Dbo class instance for testing
*
*/
public function setUp() {
$this->Dbo = ConnectionManager::getDataSource('test');
if ($this->Dbo->config['driver'] !== 'mysqli') {
$this->markTestSkipped('The MySQLi extension is not available.');
}
$this->model = new MysqliTestModel();
}
/**
* Sets up a Dbo class instance for testing
*
*/
public function tearDown() {
unset($this->model);
ClassRegistry::flush();
}
/**
* testIndexDetection method
*
* @return void
*/
public function testIndexDetection() {
$this->Dbo->cacheSources = false;
$name = $this->Dbo->fullTableName('simple');
$this->Dbo->query('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id));');
$expected = array('PRIMARY' => array('column' => 'id', 'unique' => 1));
$result = $this->Dbo->index($name, false);
$this->assertEqual($expected, $result);
$this->Dbo->query('DROP TABLE ' . $name);
$name = $this->Dbo->fullTableName('with_a_key');
$this->Dbo->query('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id), KEY `pointless_bool` ( `bool` ));');
$expected = array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
'pointless_bool' => array('column' => 'bool', 'unique' => 0),
);
$result = $this->Dbo->index($name, false);
$this->assertEqual($expected, $result);
$this->Dbo->query('DROP TABLE ' . $name);
$name = $this->Dbo->fullTableName('with_two_keys');
$this->Dbo->query('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id), KEY `pointless_bool` ( `bool` ), KEY `pointless_small_int` ( `small_int` ));');
$expected = array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
'pointless_bool' => array('column' => 'bool', 'unique' => 0),
'pointless_small_int' => array('column' => 'small_int', 'unique' => 0),
);
$result = $this->Dbo->index($name, false);
$this->assertEqual($expected, $result);
$this->Dbo->query('DROP TABLE ' . $name);
$name = $this->Dbo->fullTableName('with_compound_keys');
$this->Dbo->query('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id), KEY `pointless_bool` ( `bool` ), KEY `pointless_small_int` ( `small_int` ), KEY `one_way` ( `bool`, `small_int` ));');
$expected = array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
'pointless_bool' => array('column' => 'bool', 'unique' => 0),
'pointless_small_int' => array('column' => 'small_int', 'unique' => 0),
'one_way' => array('column' => array('bool', 'small_int'), 'unique' => 0),
);
$result = $this->Dbo->index($name, false);
$this->assertEqual($expected, $result);
$this->Dbo->query('DROP TABLE ' . $name);
$name = $this->Dbo->fullTableName('with_multiple_compound_keys');
$this->Dbo->query('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id), KEY `pointless_bool` ( `bool` ), KEY `pointless_small_int` ( `small_int` ), KEY `one_way` ( `bool`, `small_int` ), KEY `other_way` ( `small_int`, `bool` ));');
$expected = array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
'pointless_bool' => array('column' => 'bool', 'unique' => 0),
'pointless_small_int' => array('column' => 'small_int', 'unique' => 0),
'one_way' => array('column' => array('bool', 'small_int'), 'unique' => 0),
'other_way' => array('column' => array('small_int', 'bool'), 'unique' => 0),
);
$result = $this->Dbo->index($name, false);
$this->assertEqual($expected, $result);
$this->Dbo->query('DROP TABLE ' . $name);
}
/**
* testColumn method
*
* @return void
*/
public function testColumn() {
$result = $this->Dbo->column('varchar(50)');
$expected = 'string';
$this->assertEqual($result, $expected);
$result = $this->Dbo->column('text');
$expected = 'text';
$this->assertEqual($result, $expected);
$result = $this->Dbo->column('int(11)');
$expected = 'integer';
$this->assertEqual($result, $expected);
$result = $this->Dbo->column('int(11) unsigned');
$expected = 'integer';
$this->assertEqual($result, $expected);
$result = $this->Dbo->column('tinyint(1)');
$expected = 'boolean';
$this->assertEqual($result, $expected);
$result = $this->Dbo->column('boolean');
$expected = 'boolean';
$this->assertEqual($result, $expected);
$result = $this->Dbo->column('float');
$expected = 'float';
$this->assertEqual($result, $expected);
$result = $this->Dbo->column('float unsigned');
$expected = 'float';
$this->assertEqual($result, $expected);
$result = $this->Dbo->column('double unsigned');
$expected = 'float';
$this->assertEqual($result, $expected);
$result = $this->Dbo->column('decimal(14,7) unsigned');
$expected = 'float';
$this->assertEqual($result, $expected);
}
/**
* test transaction commands.
*
* @return void
*/
public function testTransactions() {
$this->Dbo->testing = false;
$result = $this->Dbo->begin($this->model);
$this->assertTrue($result);
$log = $this->Dbo->getLog();
$beginSqlCalls = Set::extract('/.[query=START TRANSACTION]', $log['log']);
$this->assertEqual(1, count($beginSqlCalls));
$result = $this->Dbo->commit($this->model);
$this->assertTrue($result);
}
/**
* test that float values are correctly identified
*
* @return void
*/
function testFloatParsing() {
$model = new Model(array('ds' => 'test', 'table' => 'datatypes', 'name' => 'Datatype'));
$result = $this->Dbo->describe($model);
$this->assertEqual((string)$result['float_field']['length'], '5,2');
}
/**
* test that tableParameters like collation, charset and engine are functioning.
*
* @access public
* @return void
*/
function testReadTableParameters() {
$table = 'tinyint' . uniqid();
$this->Dbo->cacheSources = $this->Dbo->testing = false;
$this->Dbo->query('CREATE TABLE ' . $this->Dbo->fullTableName($table) . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;');
$result = $this->Dbo->readTableParameters($table);
$expected = array(
'charset' => 'utf8',
'collate' => 'utf8_unicode_ci',
'engine' => 'InnoDB');
$this->assertEqual($result, $expected);
$this->Dbo->query('DROP TABLE ' . $this->Dbo->fullTableName($table));
$this->Dbo->query('CREATE TABLE ' . $this->Dbo->fullTableName($table) . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id)) ENGINE=MyISAM DEFAULT CHARSET=cp1250 COLLATE=cp1250_general_ci;');
$result = $this->Dbo->readTableParameters($table);
$expected = array(
'charset' => 'cp1250',
'collate' => 'cp1250_general_ci',
'engine' => 'MyISAM');
$this->assertEqual($result, $expected);
$this->Dbo->query('DROP TABLE ' . $this->Dbo->fullTableName($table));
}
}

View file

@ -244,6 +244,7 @@ class DboPostgresTest extends CakeTestCase {
public function setUp() { public function setUp() {
Configure::write('Cache.disable', true); Configure::write('Cache.disable', true);
$this->Dbo = ConnectionManager::getDataSource('test'); $this->Dbo = ConnectionManager::getDataSource('test');
$this->skipIf(!($this->Dbo instanceof DboPostgres));
$this->Dbo2 = new DboPostgresTestDb($this->Dbo->config, false); $this->Dbo2 = new DboPostgresTestDb($this->Dbo->config, false);
$this->skipUnless($this->Dbo->config['driver'] == 'postgres', 'PostgreSQL connection not available'); $this->skipUnless($this->Dbo->config['driver'] == 'postgres', 'PostgreSQL connection not available');
$this->model = new PostgresTestModel(); $this->model = new PostgresTestModel();
@ -330,30 +331,30 @@ class DboPostgresTest extends CakeTestCase {
* @return void * @return void
*/ */
function testValueQuoting() { function testValueQuoting() {
$this->assertIdentical($this->db2->value(1.2, 'float'), "'1.200000'"); $this->assertEqual($this->Dbo->value(1.2, 'float'), "1.200000");
$this->assertEqual($this->db2->value('1,2', 'float'), "'1,2'"); $this->assertEqual($this->Dbo->value('1,2', 'float'), "'1,2'");
$this->assertEqual($this->Dbo2->value('0', 'integer'), "'0'"); $this->assertEqual($this->Dbo->value('0', 'integer'), "0");
$this->assertEqual($this->Dbo2->value('', 'integer'), 'NULL'); $this->assertEqual($this->Dbo->value('', 'integer'), 'NULL');
$this->assertEqual($this->Dbo2->value('', 'float'), 'NULL'); $this->assertEqual($this->Dbo->value('', 'float'), 'NULL');
$this->assertEqual($this->Dbo2->value('', 'integer', false), "DEFAULT"); $this->assertEqual($this->Dbo->value('', 'integer', false), "NULL");
$this->assertEqual($this->Dbo2->value('', 'float', false), "DEFAULT"); $this->assertEqual($this->Dbo->value('', 'float', false), "NULL");
$this->assertEqual($this->Dbo2->value('0.0', 'float'), "'0.0'"); $this->assertEqual($this->Dbo->value('0.0', 'float'), "'0.0'");
$this->assertEqual($this->Dbo2->value('t', 'boolean'), "TRUE"); $this->assertEqual($this->Dbo->value('t', 'boolean'), "'TRUE'");
$this->assertEqual($this->Dbo2->value('f', 'boolean'), "FALSE"); $this->assertEqual($this->Dbo->value('f', 'boolean'), "'FALSE'");
$this->assertEqual($this->Dbo2->value(true), "TRUE"); $this->assertEqual($this->Dbo->value(true), "'TRUE'");
$this->assertEqual($this->Dbo2->value(false), "FALSE"); $this->assertEqual($this->Dbo->value(false), "'FALSE'");
$this->assertEqual($this->Dbo2->value('t'), "'t'"); $this->assertEqual($this->Dbo->value('t'), "'t'");
$this->assertEqual($this->Dbo2->value('f'), "'f'"); $this->assertEqual($this->Dbo->value('f'), "'f'");
$this->assertEqual($this->Dbo2->value('true', 'boolean'), 'TRUE'); $this->assertEqual($this->Dbo->value('true', 'boolean'), "'TRUE'");
$this->assertEqual($this->Dbo2->value('false', 'boolean'), 'FALSE'); $this->assertEqual($this->Dbo->value('false', 'boolean'), "'FALSE'");
$this->assertEqual($this->Dbo2->value('', 'boolean'), 'FALSE'); $this->assertEqual($this->Dbo->value('', 'boolean'), "'FALSE'");
$this->assertEqual($this->Dbo2->value(0, 'boolean'), 'FALSE'); $this->assertEqual($this->Dbo->value(0, 'boolean'), "'FALSE'");
$this->assertEqual($this->Dbo2->value(1, 'boolean'), 'TRUE'); $this->assertEqual($this->Dbo->value(1, 'boolean'), "'TRUE'");
$this->assertEqual($this->Dbo2->value('1', 'boolean'), 'TRUE'); $this->assertEqual($this->Dbo->value('1', 'boolean'), "'TRUE'");
$this->assertEqual($this->Dbo2->value(null, 'boolean'), "NULL"); $this->assertEqual($this->Dbo->value(null, 'boolean'), "NULL");
$this->assertEqual($this->Dbo2->value(array()), "NULL"); $this->assertEqual($this->Dbo->value(array()), "NULL");
} }
/** /**
@ -366,10 +367,10 @@ class DboPostgresTest extends CakeTestCase {
setlocale(LC_ALL, 'de_DE'); setlocale(LC_ALL, 'de_DE');
$result = $this->db->value(3.141593, 'float'); $result = $this->db->value(3.141593, 'float');
$this->assertEqual((string)$result, "'3.141593'"); $this->assertEqual((string)$result, "3.141593");
$result = $this->db->value(3.14); $result = $this->db->value(3.14);
$this->assertEqual((string)$result, "'3.140000'"); $this->assertEqual((string)$result, "3.140000");
setlocale(LC_ALL, $restore); setlocale(LC_ALL, $restore);
} }
@ -380,17 +381,17 @@ class DboPostgresTest extends CakeTestCase {
* @return void * @return void
*/ */
function testDateAndTimeAsNull() { function testDateAndTimeAsNull() {
$this->assertEqual($this->Dbo2->value(null, 'date'), 'NULL'); $this->assertEqual($this->Dbo->value(null, 'date'), 'NULL');
$this->assertEqual($this->Dbo2->value('', 'date'), 'NULL'); $this->assertEqual($this->Dbo->value('', 'date'), 'NULL');
$this->assertEqual($this->Dbo2->value('', 'datetime'), 'NULL'); $this->assertEqual($this->Dbo->value('', 'datetime'), 'NULL');
$this->assertEqual($this->Dbo2->value(null, 'datetime'), 'NULL'); $this->assertEqual($this->Dbo->value(null, 'datetime'), 'NULL');
$this->assertEqual($this->Dbo2->value('', 'timestamp'), 'NULL'); $this->assertEqual($this->Dbo->value('', 'timestamp'), 'NULL');
$this->assertEqual($this->Dbo2->value(null, 'timestamp'), 'NULL'); $this->assertEqual($this->Dbo->value(null, 'timestamp'), 'NULL');
$this->assertEqual($this->Dbo2->value('', 'time'), 'NULL'); $this->assertEqual($this->Dbo->value('', 'time'), 'NULL');
$this->assertEqual($this->Dbo2->value(null, 'time'), 'NULL'); $this->assertEqual($this->Dbo->value(null, 'time'), 'NULL');
} }
/** /**
@ -400,19 +401,19 @@ class DboPostgresTest extends CakeTestCase {
* @return void * @return void
*/ */
function testBooleanNormalization() { function testBooleanNormalization() {
$this->assertTrue($this->Dbo2->boolean('t')); $this->assertEquals(1, $this->Dbo2->boolean('t', false));
$this->assertTrue($this->Dbo2->boolean('true')); $this->assertEquals(1, $this->Dbo2->boolean('true', false));
$this->assertTrue($this->Dbo2->boolean('TRUE')); $this->assertEquals(1, $this->Dbo2->boolean('TRUE', false));
$this->assertTrue($this->Dbo2->boolean(true)); $this->assertEquals(1, $this->Dbo2->boolean(true, false));
$this->assertTrue($this->Dbo2->boolean(1)); $this->assertEquals(1, $this->Dbo2->boolean(1, false));
$this->assertTrue($this->Dbo2->boolean(" ")); $this->assertEquals(1, $this->Dbo2->boolean(" ", false));
$this->assertFalse($this->Dbo2->boolean('f')); $this->assertEquals(0, $this->Dbo2->boolean('f', false));
$this->assertFalse($this->Dbo2->boolean('false')); $this->assertEquals(0, $this->Dbo2->boolean('false', false));
$this->assertFalse($this->Dbo2->boolean('FALSE')); $this->assertEquals(0, $this->Dbo2->boolean('FALSE', false));
$this->assertFalse($this->Dbo2->boolean(false)); $this->assertEquals(0, $this->Dbo2->boolean(false, false));
$this->assertFalse($this->Dbo2->boolean(0)); $this->assertEquals(0, $this->Dbo2->boolean(0, false));
$this->assertFalse($this->Dbo2->boolean('')); $this->assertEquals(0, $this->Dbo2->boolean('', false));
} }
/** /**
@ -427,7 +428,7 @@ class DboPostgresTest extends CakeTestCase {
$db2 = clone $db1; $db2 = clone $db1;
$db2->connect(); $db2->connect();
$this->assertNotEqual($db1->connection, $db2->connection); $this->assertNotSame($db1->getConnection(), $db2->getConnection());
$table = $db1->fullTableName('users', false); $table = $db1->fullTableName('users', false);
$password = '5f4dcc3b5aa765d61d8327deb882cf99'; $password = '5f4dcc3b5aa765d61d8327deb882cf99';
@ -556,12 +557,12 @@ class DboPostgresTest extends CakeTestCase {
$db1 = ConnectionManager::getDataSource('test'); $db1 = ConnectionManager::getDataSource('test');
$db1->cacheSources = false; $db1->cacheSources = false;
$db1->reconnect(array('persistent' => false)); $db1->reconnect(array('persistent' => false));
$db1->query('CREATE TABLE ' . $db1->fullTableName('datatypes') . ' ( $db1->rawQuery('CREATE TABLE ' . $db1->fullTableName('datatypes') . ' (
id serial NOT NULL, id serial NOT NULL,
"varchar" character varying(40) NOT NULL, "varchar" character varying(40) NOT NULL,
"full_length" character varying NOT NULL, "full_length" character varying NOT NULL,
"timestamp" timestamp without time zone, "timestamp" timestamp without time zone,
date date, "date" date,
CONSTRAINT test_data_types_pkey PRIMARY KEY (id) CONSTRAINT test_data_types_pkey PRIMARY KEY (id)
)'); )');
$model = new Model(array('name' => 'Datatype', 'ds' => 'test')); $model = new Model(array('name' => 'Datatype', 'ds' => 'test'));
@ -570,21 +571,21 @@ class DboPostgresTest extends CakeTestCase {
'connection' => 'test', 'connection' => 'test',
'models' => array('Datatype') 'models' => array('Datatype')
)); ));
$schema->tables = array('datatypes' => $result['tables']['datatypes']);
$schema->tables = array('datatypes' => $result['tables']['missing']['datatypes']);
$result = $db1->createSchema($schema, 'datatypes'); $result = $db1->createSchema($schema, 'datatypes');
$db1->rawQuery('DROP TABLE ' . $db1->fullTableName('datatypes'));
$this->assertNoPattern('/timestamp DEFAULT/', $result); $this->assertNoPattern('/timestamp DEFAULT/', $result);
$this->assertPattern('/\"full_length\"\s*text\s.*,/', $result); $this->assertPattern('/\"full_length\"\s*text\s.*,/', $result);
$this->assertPattern('/timestamp\s*,/', $result); $this->assertPattern('/timestamp\s*,/', $result);
$db1->query('DROP TABLE ' . $db1->fullTableName('datatypes'));
$db1->query($result); $db1->query($result);
$result2 = $schema->read(array( $result2 = $schema->read(array(
'connection' => 'test', 'connection' => 'test',
'models' => array('Datatype') 'models' => array('Datatype')
)); ));
$schema->tables = array('datatypes' => $result2['tables']['datatypes']); $schema->tables = array('datatypes' => $result2['tables']['missing']['datatypes']);
$result2 = $db1->createSchema($schema, 'datatypes'); $result2 = $db1->createSchema($schema, 'datatypes');
$this->assertEqual($result, $result2); $this->assertEqual($result, $result2);
@ -602,25 +603,25 @@ class DboPostgresTest extends CakeTestCase {
$this->Dbo->query('CREATE INDEX pointless_bool ON ' . $name . '("bool")'); $this->Dbo->query('CREATE INDEX pointless_bool ON ' . $name . '("bool")');
$this->Dbo->query('CREATE UNIQUE INDEX char_index ON ' . $name . '("small_char")'); $this->Dbo->query('CREATE UNIQUE INDEX char_index ON ' . $name . '("small_char")');
$expected = array( $expected = array(
'PRIMARY' => array('column' => 'id', 'unique' => true), 'PRIMARY' => array('column' => 'id', 'unique' => 1),
'pointless_bool' => array('column' => 'bool', 'unique' => false), 'pointless_bool' => array('column' => 'bool', 'unique' => 0),
'char_index' => array('column' => 'small_char', 'unique' => true), 'char_index' => array('column' => 'small_char', 'unique' => 1),
); );
$result = $this->Dbo->index($name); $result = $this->Dbo->index($name);
$this->Dbo->query('DROP TABLE ' . $name);
$this->assertEqual($expected, $result); $this->assertEqual($expected, $result);
$this->Dbo->query('DROP TABLE ' . $name);
$name = $this->Dbo->fullTableName('index_test_2', false); $name = $this->Dbo->fullTableName('index_test_2', false);
$this->Dbo->query('CREATE TABLE ' . $name . ' ("id" serial NOT NULL PRIMARY KEY, "bool" integer, "small_char" varchar(50), "description" varchar(40) )'); $this->Dbo->query('CREATE TABLE ' . $name . ' ("id" serial NOT NULL PRIMARY KEY, "bool" integer, "small_char" varchar(50), "description" varchar(40) )');
$this->Dbo->query('CREATE UNIQUE INDEX multi_col ON ' . $name . '("small_char", "bool")'); $this->Dbo->query('CREATE UNIQUE INDEX multi_col ON ' . $name . '("small_char", "bool")');
$expected = array( $expected = array(
'PRIMARY' => array('column' => 'id', 'unique' => true), 'PRIMARY' => array('column' => 'id', 'unique' => 1),
'multi_col' => array('column' => array('small_char', 'bool'), 'unique' => true), 'multi_col' => array('column' => array('small_char', 'bool'), 'unique' => 1),
); );
$result = $this->Dbo->index($name); $result = $this->Dbo->index($name);
$this->assertEqual($expected, $result);
$this->Dbo->query('DROP TABLE ' . $name); $this->Dbo->query('DROP TABLE ' . $name);
$this->assertEqual($expected, $result);
} }
/** /**
@ -691,21 +692,21 @@ class DboPostgresTest extends CakeTestCase {
'group2' => array('type' => 'integer', 'null' => true) 'group2' => array('type' => 'integer', 'null' => true)
) )
)); ));
$this->Dbo->query($this->Dbo->createSchema($schema1)); $this->Dbo->rawQuery($this->Dbo->createSchema($schema1));
$schema2 = new CakeSchema(array( $schema2 = new CakeSchema(array(
'name' => 'AlterTest2', 'name' => 'AlterTest2',
'connection' => 'test', 'connection' => 'test',
'altertest' => array( 'altertest' => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => 0), 'id' => array('type' => 'integer', 'null' => 0, 'default' => 0),
'name' => array('type' => 'string', 'null' => false, 'length' => 50), 'name' => array('type' => 'string', 'null' => 0, 'length' => 50),
'group1' => array('type' => 'integer', 'null' => true), 'group1' => array('type' => 'integer', 'null' => 1),
'group2' => array('type' => 'integer', 'null' => true), 'group2' => array('type' => 'integer', 'null' => 1),
'indexes' => array( 'indexes' => array(
'name_idx' => array('column' => 'name', 'unique' => false), 'name_idx' => array('column' => 'name', 'unique' => 0),
'group_idx' => array('column' => 'group1', 'unique' => false), 'group_idx' => array('column' => 'group1', 'unique' => 0),
'compound_idx' => array('column' => array('group1', 'group2'), 'unique' => false), 'compound_idx' => array('column' => array('group1', 'group2'), 'unique' => 0),
'PRIMARY' => array('column' => 'id', 'unique' => true) 'PRIMARY' => array('column' => 'id', 'unique' => 1)
) )
) )
)); ));
@ -719,15 +720,15 @@ class DboPostgresTest extends CakeTestCase {
'name' => 'AlterTest3', 'name' => 'AlterTest3',
'connection' => 'test', 'connection' => 'test',
'altertest' => array( 'altertest' => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => 0), 'id' => array('type' => 'integer', 'null' => 0, 'default' => 0),
'name' => array('type' => 'string', 'null' => false, 'length' => 50), 'name' => array('type' => 'string', 'null' => 0, 'length' => 50),
'group1' => array('type' => 'integer', 'null' => true), 'group1' => array('type' => 'integer', 'null' => 1),
'group2' => array('type' => 'integer', 'null' => true), 'group2' => array('type' => 'integer', 'null' => 1),
'indexes' => array( 'indexes' => array(
'name_idx' => array('column' => 'name', 'unique' => true), 'name_idx' => array('column' => 'name', 'unique' => 1),
'group_idx' => array('column' => 'group2', 'unique' => false), 'group_idx' => array('column' => 'group2', 'unique' => 0),
'compound_idx' => array('column' => array('group2', 'group1'), 'unique' => false), 'compound_idx' => array('column' => array('group2', 'group1'), 'unique' => 0),
'another_idx' => array('column' => array('group1', 'name'), 'unique' => false)) 'another_idx' => array('column' => array('group1', 'name'), 'unique' => 0))
))); )));
$this->Dbo->query($this->Dbo->alterSchema($schema3->compare($schema2))); $this->Dbo->query($this->Dbo->alterSchema($schema3->compare($schema2)));

View file

@ -90,14 +90,6 @@ class DboSqliteTest extends CakeTestCase {
*/ */
public $Dbo = null; public $Dbo = null;
/**
* Simulated DB connection used in testing
*
* @var DboSource
* @access public
*/
public $Dbo2 = null;
/** /**
* Sets up a Dbo class instance for testing * Sets up a Dbo class instance for testing
* *
@ -108,7 +100,6 @@ class DboSqliteTest extends CakeTestCase {
if ($this->Dbo->config['driver'] !== 'sqlite') { if ($this->Dbo->config['driver'] !== 'sqlite') {
$this->markTestSkipped('The Sqlite extension is not available.'); $this->markTestSkipped('The Sqlite extension is not available.');
} }
$this->Dbo2 = new DboSqliteTestDb($this->Dbo->config, false);
} }
/** /**
@ -117,7 +108,6 @@ class DboSqliteTest extends CakeTestCase {
*/ */
public function tearDown() { public function tearDown() {
Configure::write('Cache.disable', false); Configure::write('Cache.disable', false);
unset($this->Dbo2);
} }
/** /**
@ -127,10 +117,11 @@ class DboSqliteTest extends CakeTestCase {
public function testTableListCacheDisabling() { public function testTableListCacheDisabling() {
$this->assertFalse(in_array('foo_test', $this->Dbo->listSources())); $this->assertFalse(in_array('foo_test', $this->Dbo->listSources()));
$this->Dbo->query('CREATE TABLE foo_test (test VARCHAR(255));'); $this->Dbo->query('CREATE TABLE foo_test (test VARCHAR(255))');
$this->assertTrue(in_array('foo_test', $this->Dbo->listSources())); $this->assertTrue(in_array('foo_test', $this->Dbo->listSources()));
$this->Dbo->query('DROP TABLE foo_test;'); $this->Dbo->cacheSources = false;
$this->Dbo->query('DROP TABLE foo_test');
$this->assertFalse(in_array('foo_test', $this->Dbo->listSources())); $this->assertFalse(in_array('foo_test', $this->Dbo->listSources()));
} }
@ -207,7 +198,7 @@ class DboSqliteTest extends CakeTestCase {
'null' => false, 'null' => false,
); );
$result = $this->Dbo->buildColumn($data); $result = $this->Dbo->buildColumn($data);
$expected = '"int_field" integer(11) NOT NULL'; $expected = '"int_field" integer NOT NULL';
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
$data = array( $data = array(
@ -251,7 +242,7 @@ class DboSqliteTest extends CakeTestCase {
'null' => false, 'null' => false,
); );
$result = $this->Dbo->buildColumn($data); $result = $this->Dbo->buildColumn($data);
$expected = '"testName" integer(10) DEFAULT \'10\' NOT NULL'; $expected = '"testName" integer(10) DEFAULT 10 NOT NULL';
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
$data = array( $data = array(
@ -263,7 +254,7 @@ class DboSqliteTest extends CakeTestCase {
'collate' => 'BADVALUE' 'collate' => 'BADVALUE'
); );
$result = $this->Dbo->buildColumn($data); $result = $this->Dbo->buildColumn($data);
$expected = '"testName" integer(10) DEFAULT \'10\' NOT NULL'; $expected = '"testName" integer(10) DEFAULT 10 NOT NULL';
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
} }

File diff suppressed because it is too large Load diff

View file

@ -184,7 +184,7 @@ class ModelIntegrationTest extends BaseModelTest {
*/ */
function testPkInHabtmLinkModel() { function testPkInHabtmLinkModel() {
//Test Nonconformant Models //Test Nonconformant Models
$this->loadFixtures('Content', 'ContentAccount', 'Account', 'JoinC', 'JoinAC'); $this->loadFixtures('Content', 'ContentAccount', 'Account', 'JoinC', 'JoinAC', 'ItemsPortfolio');
$TestModel = new Content(); $TestModel = new Content();
$this->assertEqual($TestModel->ContentAccount->primaryKey, 'iContentAccountsId'); $this->assertEqual($TestModel->ContentAccount->primaryKey, 'iContentAccountsId');
@ -1867,7 +1867,7 @@ class ModelIntegrationTest extends BaseModelTest {
* @return void * @return void
*/ */
function testCreation() { function testCreation() {
$this->loadFixtures('Article', 'ArticleFeaturedsTags'); $this->loadFixtures('Article', 'ArticleFeaturedsTags', 'User', 'Featured');
$TestModel = new Test(); $TestModel = new Test();
$result = $TestModel->create(); $result = $TestModel->create();
$expected = array('Test' => array('notes' => 'write some notes here')); $expected = array('Test' => array('notes' => 'write some notes here'));
@ -1882,9 +1882,10 @@ class ModelIntegrationTest extends BaseModelTest {
} else { } else {
$intLength = 11; $intLength = 11;
} }
foreach (array('collate', 'charset') as $type) { foreach (array('collate', 'charset', 'comment') as $type) {
unset($result['user'][$type]); foreach ($result as $i => $r) {
unset($result['password'][$type]); unset($result[$i][$type]);
}
} }
$expected = array( $expected = array(
@ -1946,8 +1947,8 @@ class ModelIntegrationTest extends BaseModelTest {
'Featured' => array( 'Featured' => array(
'article_featured_id' => 1, 'article_featured_id' => 1,
'category_id' => 1, 'category_id' => 1,
'published_date' => '2008-6-11 00:00:00', 'published_date' => '2008-06-11 00:00:00',
'end_date' => '2008-6-20 00:00:00' 'end_date' => '2008-06-20 00:00:00'
)); ));
$this->assertEqual($FeaturedModel->create($data), $expected); $this->assertEqual($FeaturedModel->create($data), $expected);
@ -1969,8 +1970,8 @@ class ModelIntegrationTest extends BaseModelTest {
$expected = array( $expected = array(
'Featured' => array( 'Featured' => array(
'published_date' => '2008-6-11 00:00:00', 'published_date' => '2008-06-11 00:00:00',
'end_date' => '2008-6-20 00:00:00', 'end_date' => '2008-06-20 00:00:00',
'article_featured_id' => 1, 'article_featured_id' => 1,
'category_id' => 1 'category_id' => 1
)); ));

View file

@ -52,15 +52,17 @@ class ModelReadTest extends BaseModelTest {
) )
); );
$Something->JoinThing->create($joinThingData); $Something->JoinThing->create($joinThingData);
$Something->JoinThing->save(); $Something->JoinThing->save();
$result = $Something->JoinThing->find('all', array('conditions' => array('something_else_id' => 2))); $result = $Something->JoinThing->find('all', array('conditions' => array('something_else_id' => 2)));
$this->assertEqual($result[0]['JoinThing']['doomed'], '1'); $this->assertEqual((bool)$result[0]['JoinThing']['doomed'], true);
$this->assertEqual($result[1]['JoinThing']['doomed'], '0'); $this->assertEqual((bool)$result[1]['JoinThing']['doomed'], false);
$result = $Something->find('first'); $result = $Something->find('first');
$this->assertEqual(count($result['SomethingElse']), 2); $this->assertEqual(count($result['SomethingElse']), 2);
$doomed = Set::extract('/JoinThing/doomed', $result['SomethingElse']); $doomed = Set::extract('/JoinThing/doomed', $result['SomethingElse']);
@ -79,7 +81,7 @@ class ModelReadTest extends BaseModelTest {
*/ */
function testGroupBy() { function testGroupBy() {
$db = ConnectionManager::getDataSource('test'); $db = ConnectionManager::getDataSource('test');
$isStrictGroupBy = in_array($db->config['driver'], array('postgres', 'oracle')); $isStrictGroupBy = in_array($db->config['driver'], array('postgres', 'oracle', 'sqlite'));
$message = '%s Postgres and Oracle have strict GROUP BY and are incompatible with this test.'; $message = '%s Postgres and Oracle have strict GROUP BY and are incompatible with this test.';
if ($this->skipIf($isStrictGroupBy, $message )) { if ($this->skipIf($isStrictGroupBy, $message )) {
@ -279,13 +281,6 @@ class ModelReadTest extends BaseModelTest {
$this->loadFixtures('Article', 'User', 'Tag', 'ArticlesTag'); $this->loadFixtures('Article', 'User', 'Tag', 'ArticlesTag');
$Article = new Article(); $Article = new Article();
$finalQuery = 'SELECT title, published FROM ';
$finalQuery .= $this->db->fullTableName('articles');
$finalQuery .= ' WHERE ' . $this->db->fullTableName('articles');
$finalQuery .= '.id = ' . $this->db->value(1);
$finalQuery .= ' AND ' . $this->db->fullTableName('articles');
$finalQuery .= '.published = ' . $this->db->value('Y');
$query = 'SELECT title, published FROM '; $query = 'SELECT title, published FROM ';
$query .= $this->db->fullTableName('articles'); $query .= $this->db->fullTableName('articles');
$query .= ' WHERE ' . $this->db->fullTableName('articles'); $query .= ' WHERE ' . $this->db->fullTableName('articles');
@ -305,14 +300,9 @@ class ModelReadTest extends BaseModelTest {
} }
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
$result = $this->db->getQueryCache($finalQuery); $result = $this->db->getQueryCache($query, $params);
$this->assertFalse(empty($result)); $this->assertFalse(empty($result));
$finalQuery = 'SELECT id, created FROM ';
$finalQuery .= $this->db->fullTableName('articles');
$finalQuery .= ' WHERE ' . $this->db->fullTableName('articles');
$finalQuery .= '.title = ' . $this->db->value('First Article');
$query = 'SELECT id, created FROM '; $query = 'SELECT id, created FROM ';
$query .= $this->db->fullTableName('articles'); $query .= $this->db->fullTableName('articles');
$query .= ' WHERE ' . $this->db->fullTableName('articles') . '.title = ?'; $query .= ' WHERE ' . $this->db->fullTableName('articles') . '.title = ?';
@ -324,7 +314,7 @@ class ModelReadTest extends BaseModelTest {
isset($result[0][$this->db->fullTableName('articles', false)]) isset($result[0][$this->db->fullTableName('articles', false)])
|| isset($result[0][0]) || isset($result[0][0])
); );
$result = $this->db->getQueryCache($finalQuery); $result = $this->db->getQueryCache($query, $params);
$this->assertTrue(empty($result)); $this->assertTrue(empty($result));
$query = 'SELECT title FROM '; $query = 'SELECT title FROM ';
@ -345,10 +335,7 @@ class ModelReadTest extends BaseModelTest {
$params = array('First? Article', 'Y'); $params = array('First? Article', 'Y');
$Article->query($query, $params); $Article->query($query, $params);
$expected = 'SELECT title FROM '; $result = $this->db->getQueryCache($query, $params);
$expected .= $this->db->fullTableName('articles');
$expected .= " WHERE title = 'First? Article' AND published = 'Y'";
$result = $this->db->getQueryCache($expected);
$this->assertFalse($result === false); $this->assertFalse($result === false);
} }
@ -5091,7 +5078,7 @@ class ModelReadTest extends BaseModelTest {
'typ' => 2 'typ' => 2
))); )));
$this->assertEqual($result, $expected); $this->assertEqual($expected, $result);
} }
/** /**
@ -5661,7 +5648,7 @@ class ModelReadTest extends BaseModelTest {
'name' => 'computer' 'name' => 'computer'
)))))); ))))));
$this->assertIdentical($result, $expected); $this->assertEquals($result, $expected);
} }
/** /**
@ -7478,7 +7465,7 @@ class ModelReadTest extends BaseModelTest {
$result = $Post->field('other_field'); $result = $Post->field('other_field');
$this->assertEqual($result, 4); $this->assertEqual($result, 4);
if ($this->skipIf($this->db->config['driver'] == 'postgres', 'The rest of virtualFieds test is not compatible with Postgres')) { if ($this->skipIf($this->db->config['driver'] != 'mysql', 'The rest of virtualFieds test is not compatible with Postgres')) {
return; return;
} }
ClassRegistry::flush(); ClassRegistry::flush();
@ -7486,20 +7473,20 @@ class ModelReadTest extends BaseModelTest {
$Post->create(); $Post->create();
$Post->virtualFields = array( $Post->virtualFields = array(
'year' => 'YEAR(Post.created)', 'low_title' => 'lower(Post.title)',
'unique_test_field' => 'COUNT(Post.id)' 'unique_test_field' => 'COUNT(Post.id)'
); );
$expectation = array( $expectation = array(
'Post' => array( 'Post' => array(
'year' => 2007, 'low_title' => 'first post',
'unique_test_field' => 3 'unique_test_field' => 1
) )
); );
$result = $Post->find('first', array( $result = $Post->find('first', array(
'fields' => array_keys($Post->virtualFields), 'fields' => array_keys($Post->virtualFields),
'group' => array('year') 'group' => array('low_title')
)); ));
$this->assertEqual($result, $expectation); $this->assertEqual($result, $expectation);

View file

@ -201,8 +201,8 @@ class ModelWriteTest extends BaseModelTest {
$TestModel->create(array()); $TestModel->create(array());
$TestModel->save(); $TestModel->save();
$result = $TestModel->findById($TestModel->id); $result = $TestModel->findById($TestModel->id);
$this->assertIdentical($result['DataTest']['count'], '0'); $this->assertEquals($result['DataTest']['count'], 0);
$this->assertIdentical($result['DataTest']['float'], '0'); $this->assertEquals($result['DataTest']['float'], 0);
} }
/** /**
@ -286,20 +286,20 @@ class ModelWriteTest extends BaseModelTest {
)); ));
$result = $TestModel->findById(1); $result = $TestModel->findById(1);
$this->assertIdentical($result['Syfile']['item_count'], '2'); $this->assertEquals($result['Syfile']['item_count'], 2);
$TestModel2->delete(1); $TestModel2->delete(1);
$result = $TestModel->findById(1); $result = $TestModel->findById(1);
$this->assertIdentical($result['Syfile']['item_count'], '1'); $this->assertEquals($result['Syfile']['item_count'], 1);
$TestModel2->id = 2; $TestModel2->id = 2;
$TestModel2->saveField('syfile_id', 1); $TestModel2->saveField('syfile_id', 1);
$result = $TestModel->findById(1); $result = $TestModel->findById(1);
$this->assertIdentical($result['Syfile']['item_count'], '2'); $this->assertEquals($result['Syfile']['item_count'], 2);
$result = $TestModel->findById(2); $result = $TestModel->findById(2);
$this->assertIdentical($result['Syfile']['item_count'], '0'); $this->assertEquals($result['Syfile']['item_count'], 0);
} }
/** /**
@ -437,7 +437,7 @@ class ModelWriteTest extends BaseModelTest {
* @return void * @return void
*/ */
function testSaveWithCounterCacheScope() { function testSaveWithCounterCacheScope() {
$this->loadFixtures('Syfile', 'Item'); $this->loadFixtures('Syfile', 'Item', 'Image', 'ItemsPortfolio', 'Portfolio');
$TestModel = new Syfile(); $TestModel = new Syfile();
$TestModel2 = new Item(); $TestModel2 = new Item();
$TestModel2->belongsTo['Syfile']['counterCache'] = true; $TestModel2->belongsTo['Syfile']['counterCache'] = true;
@ -453,12 +453,13 @@ class ModelWriteTest extends BaseModelTest {
)); ));
$result = $TestModel->findById(1); $result = $TestModel->findById(1);
$this->assertIdentical($result['Syfile']['item_count'], '1');
$this->assertEquals($result['Syfile']['item_count'], 1);
$TestModel2->id = 1; $TestModel2->id = 1;
$TestModel2->saveField('published', true); $TestModel2->saveField('published', true);
$result = $TestModel->findById(1); $result = $TestModel->findById(1);
$this->assertIdentical($result['Syfile']['item_count'], '2'); $this->assertEquals($result['Syfile']['item_count'], 2);
$TestModel2->save(array( $TestModel2->save(array(
'id' => 1, 'id' => 1,
@ -467,7 +468,7 @@ class ModelWriteTest extends BaseModelTest {
)); ));
$result = $TestModel->findById(1); $result = $TestModel->findById(1);
$this->assertIdentical($result['Syfile']['item_count'], '1'); $this->assertEquals($result['Syfile']['item_count'], 1);
} }
/** /**
@ -1013,6 +1014,7 @@ class ModelWriteTest extends BaseModelTest {
* @return void * @return void
*/ */
function testSaveFromXml() { function testSaveFromXml() {
$this->markTestSkipped('This feature needs to be fixed or dropped');
$this->loadFixtures('Article'); $this->loadFixtures('Article');
App::import('Core', 'Xml'); App::import('Core', 'Xml');
@ -1579,7 +1581,7 @@ class ModelWriteTest extends BaseModelTest {
'DoomedSomethingElse' => array( 'DoomedSomethingElse' => array(
'className' => 'SomethingElse', 'className' => 'SomethingElse',
'joinTable' => 'join_things', 'joinTable' => 'join_things',
'conditions' => 'JoinThing.doomed = true', 'conditions' => array('JoinThing.doomed' => true),
'unique' => true 'unique' => true
), ),
'NotDoomedSomethingElse' => array( 'NotDoomedSomethingElse' => array(
@ -2434,7 +2436,7 @@ class ModelWriteTest extends BaseModelTest {
* @return void * @return void
*/ */
function testSaveAll() { function testSaveAll() {
$this->loadFixtures('Post', 'Author', 'Comment', 'Attachment'); $this->loadFixtures('Post', 'Author', 'Comment', 'Attachment', 'Article', 'User');
$TestModel = new Post(); $TestModel = new Post();
$result = $TestModel->find('all'); $result = $TestModel->find('all');
@ -2574,7 +2576,7 @@ class ModelWriteTest extends BaseModelTest {
* @return void * @return void
*/ */
function testSaveAllHabtm() { function testSaveAllHabtm() {
$this->loadFixtures('Article', 'Tag', 'Comment', 'User'); $this->loadFixtures('Article', 'Tag', 'Comment', 'User', 'ArticlesTag');
$data = array( $data = array(
'Article' => array( 'Article' => array(
'user_id' => 1, 'user_id' => 1,
@ -3839,8 +3841,8 @@ class ModelWriteTest extends BaseModelTest {
*/ */
function testProductUpdateAll() { function testProductUpdateAll() {
$this->skipIf( $this->skipIf(
$this->db->config['driver'] == 'postgres', $this->db->config['driver'] != 'mysql',
'%s Currently, there is no way of doing joins in an update statement in postgresql' '%s Currently, there is no way of doing joins in an update statement in postgresql or sqlite'
); );
$this->loadFixtures('ProductUpdateAll', 'GroupUpdateAll'); $this->loadFixtures('ProductUpdateAll', 'GroupUpdateAll');
$ProductUpdateAll = new ProductUpdateAll(); $ProductUpdateAll = new ProductUpdateAll();
@ -3890,7 +3892,7 @@ class ModelWriteTest extends BaseModelTest {
*/ */
function testProductUpdateAllWithoutForeignKey() { function testProductUpdateAllWithoutForeignKey() {
$this->skipIf( $this->skipIf(
$this->db->config['driver'] == 'postgres', $this->db->config['driver'] != 'mysql',
'%s Currently, there is no way of doing joins in an update statement in postgresql' '%s Currently, there is no way of doing joins in an update statement in postgresql'
); );
$this->loadFixtures('ProductUpdateAll', 'GroupUpdateAll'); $this->loadFixtures('ProductUpdateAll', 'GroupUpdateAll');

File diff suppressed because it is too large Load diff

View file

@ -57,17 +57,17 @@ class AcoFixture extends CakeTestFixture {
* @access public * @access public
*/ */
public $records = array( public $records = array(
array('parent_id' => null, 'model' => null, 'foreign_key' => null, 'alias' => 'ROOT', 'lft' => 1, 'rght' => 24), array('id' => 1, 'parent_id' => null, 'model' => null, 'foreign_key' => null, 'alias' => 'ROOT', 'lft' => 1, 'rght' => 24),
array('parent_id' => 1, 'model' => null, 'foreign_key' => null, 'alias' => 'Controller1', 'lft' => 2, 'rght' => 9), array('id' => 2, 'parent_id' => 1, 'model' => null, 'foreign_key' => null, 'alias' => 'Controller1', 'lft' => 2, 'rght' => 9),
array('parent_id' => 2, 'model' => null, 'foreign_key' => null, 'alias' => 'action1', 'lft' => 3, 'rght' => 6), array('id' => 3, 'parent_id' => 2, 'model' => null, 'foreign_key' => null, 'alias' => 'action1', 'lft' => 3, 'rght' => 6),
array('parent_id' => 3, 'model' => null, 'foreign_key' => null, 'alias' => 'record1', 'lft' => 4, 'rght' => 5), array('id' => 4, 'parent_id' => 3, 'model' => null, 'foreign_key' => null, 'alias' => 'record1', 'lft' => 4, 'rght' => 5),
array('parent_id' => 2, 'model' => null, 'foreign_key' => null, 'alias' => 'action2', 'lft' => 7, 'rght' => 8), array('id' => 5, 'parent_id' => 2, 'model' => null, 'foreign_key' => null, 'alias' => 'action2', 'lft' => 7, 'rght' => 8),
array('parent_id' => 1, 'model' => null, 'foreign_key' => null, 'alias' => 'Controller2','lft' => 10, 'rght' => 17), array('id' => 6, 'parent_id' => 1, 'model' => null, 'foreign_key' => null, 'alias' => 'Controller2','lft' => 10, 'rght' => 17),
array('parent_id' => 6, 'model' => null, 'foreign_key' => null, 'alias' => 'action1', 'lft' => 11, 'rght' => 14), array('id' => 7, 'parent_id' => 6, 'model' => null, 'foreign_key' => null, 'alias' => 'action1', 'lft' => 11, 'rght' => 14),
array('parent_id' => 7, 'model' => null, 'foreign_key' => null, 'alias' => 'record1', 'lft' => 12, 'rght' => 13), array('id' => 8, 'parent_id' => 7, 'model' => null, 'foreign_key' => null, 'alias' => 'record1', 'lft' => 12, 'rght' => 13),
array('parent_id' => 6, 'model' => null, 'foreign_key' => null, 'alias' => 'action2', 'lft' => 15, 'rght' => 16), array('id' => 9, 'parent_id' => 6, 'model' => null, 'foreign_key' => null, 'alias' => 'action2', 'lft' => 15, 'rght' => 16),
array('parent_id' => 1, 'model' => null, 'foreign_key' => null, 'alias' => 'Users', 'lft' => 18, 'rght' => 23), array('id' => 10, 'parent_id' => 1, 'model' => null, 'foreign_key' => null, 'alias' => 'Users', 'lft' => 18, 'rght' => 23),
array('parent_id' => 9, 'model' => null, 'foreign_key' => null, 'alias' => 'Users', 'lft' => 19, 'rght' => 22), array('id' => 11, 'parent_id' => 9, 'model' => null, 'foreign_key' => null, 'alias' => 'Users', 'lft' => 19, 'rght' => 22),
array('parent_id' => 10, 'model' => null, 'foreign_key' => null, 'alias' => 'view', 'lft' => 20, 'rght' => 21), array('id' => 12, 'parent_id' => 10, 'model' => null, 'foreign_key' => null, 'alias' => 'view', 'lft' => 20, 'rght' => 21),
); );
} }

View file

@ -64,23 +64,23 @@ class TranslateFixture extends CakeTestFixture {
* @access public * @access public
*/ */
public $records = array( public $records = array(
array('id' => 1, 'locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'title', 'content' => 'Title #1'), array('locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'title', 'content' => 'Title #1'),
array('id' => 2, 'locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'content', 'content' => 'Content #1'), array('locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'content', 'content' => 'Content #1'),
array('id' => 3, 'locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'title', 'content' => 'Titel #1'), array('locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'title', 'content' => 'Titel #1'),
array('id' => 4, 'locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'content', 'content' => 'Inhalt #1'), array('locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'content', 'content' => 'Inhalt #1'),
array('id' => 5, 'locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'title', 'content' => 'Titulek #1'), array('locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'title', 'content' => 'Titulek #1'),
array('id' => 6, 'locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'content', 'content' => 'Obsah #1'), array('locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 1, 'field' => 'content', 'content' => 'Obsah #1'),
array('id' => 7, 'locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'title', 'content' => 'Title #2'), array('locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'title', 'content' => 'Title #2'),
array('id' => 8, 'locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'content', 'content' => 'Content #2'), array('locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'content', 'content' => 'Content #2'),
array('id' => 9, 'locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'title', 'content' => 'Titel #2'), array('locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'title', 'content' => 'Titel #2'),
array('id' => 10, 'locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'content', 'content' => 'Inhalt #2'), array('locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'content', 'content' => 'Inhalt #2'),
array('id' => 11, 'locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'title', 'content' => 'Titulek #2'), array('locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'title', 'content' => 'Titulek #2'),
array('id' => 12, 'locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'content', 'content' => 'Obsah #2'), array('locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 2, 'field' => 'content', 'content' => 'Obsah #2'),
array('id' => 13, 'locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'title', 'content' => 'Title #3'), array('locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'title', 'content' => 'Title #3'),
array('id' => 14, 'locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'content', 'content' => 'Content #3'), array('locale' => 'eng', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'content', 'content' => 'Content #3'),
array('id' => 15, 'locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'title', 'content' => 'Titel #3'), array('locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'title', 'content' => 'Titel #3'),
array('id' => 16, 'locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'content', 'content' => 'Inhalt #3'), array('locale' => 'deu', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'content', 'content' => 'Inhalt #3'),
array('id' => 17, 'locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'title', 'content' => 'Titulek #3'), array('locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'title', 'content' => 'Titulek #3'),
array('id' => 18, 'locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'content', 'content' => 'Obsah #3') array('locale' => 'cze', 'model' => 'TranslatedItem', 'foreign_key' => 3, 'field' => 'content', 'content' => 'Obsah #3')
); );
} }

View file

@ -177,8 +177,8 @@ class CakeFixtureManager {
$cacheSources = $db->cacheSources; $cacheSources = $db->cacheSources;
$db->cacheSources = false; $db->cacheSources = false;
$db->cacheSources = $cacheSources;
$sources = $db->listSources(); $sources = $db->listSources();
$db->cacheSources = $cacheSources;
$table = $db->config['prefix'] . $fixture->table; $table = $db->config['prefix'] . $fixture->table;
if ($drop && in_array($table, $sources)) { if ($drop && in_array($table, $sources)) {
@ -206,6 +206,7 @@ class CakeFixtureManager {
return; return;
} }
$test->db->begin();
foreach ($fixtures as $f) { foreach ($fixtures as $f) {
if (!empty($this->_loaded[$f])) { if (!empty($this->_loaded[$f])) {
$fixture = $this->_loaded[$f]; $fixture = $this->_loaded[$f];
@ -213,6 +214,7 @@ class CakeFixtureManager {
$fixture->insert($test->db); $fixture->insert($test->db);
} }
} }
$test->db->commit();
} }
/** /**

View file

@ -165,11 +165,10 @@ class CakeTestFixture {
public function insert(&$db) { public function insert(&$db) {
if (!isset($this->_insert)) { if (!isset($this->_insert)) {
$values = array(); $values = array();
if (isset($this->records) && !empty($this->records)) { if (isset($this->records) && !empty($this->records)) {
foreach ($this->records as $record) { foreach ($this->records as $record) {
$fields = array_keys($record); $fields = array_keys($record);
$values[] = '(' . implode(', ', array_map(array(&$db, 'value'), array_values($record))) . ')'; $values[] = array_values($record);
} }
return $db->insertMulti($this->table, $fields, $values); return $db->insertMulti($this->table, $fields, $values);
} }

View file

@ -263,7 +263,7 @@ class DataSource extends Object {
* @param Model $model * @param Model $model
* @return array Array of Metadata for the $model * @return array Array of Metadata for the $model
*/ */
public function describe(&$model) { public function describe($model) {
if ($this->cacheSources === false) { if ($this->cacheSources === false) {
return null; return null;
} }
@ -556,7 +556,7 @@ class DataSource extends Object {
* @param string $key Key name to make * @param string $key Key name to make
* @return string Key name for model. * @return string Key name for model.
*/ */
public function resolveKey(&$model, $key) { public function resolveKey($model, $key) {
return $model->alias . $key; return $model->alias . $key;
} }

View file

@ -88,6 +88,22 @@ class DboSource extends DataSource {
*/ */
private $__sqlOps = array('like', 'ilike', 'or', 'not', 'in', 'between', 'regexp', 'similar to'); private $__sqlOps = array('like', 'ilike', 'or', 'not', 'in', 'between', 'regexp', 'similar to');
/**
* Indicates that a transaction have been started
*
* @var boolean
* @access protected
*/
protected $_transactionStarted = false;
/**
* Indicates the level of nested transactions
*
* @var integer
* @access protected
*/
protected $_transactionNesting = 0;
/** /**
* Index of basic SQL commands * Index of basic SQL commands
* *
@ -160,18 +176,37 @@ class DboSource extends DataSource {
} }
/** /**
* Prepares a value, or an array of values for database queries by quoting and escaping them. * Disconnects from database.
* *
* @param mixed $data A value or an array of values to prepare. * @return boolean True if the database could be disconnected, else false
* @param string $column The column into which this data will be inserted
* @param boolean $read Value to be used in READ or WRITE context
* @return mixed Prepared value or array of values.
*/ */
public function value($data, $column = null, $read = true) { function disconnect() {
if (is_a($this->_result, 'PDOStatement')) {
$this->_result->closeCursor();
}
unset($this->_connection);
$this->connected = false;
return !$this->connected;
}
public function getConnection() {
return $this->_connection;
}
/**
* Returns a quoted and escaped string of $data for use in an SQL statement.
*
* @param string $data String to be prepared for use in an SQL statement
* @param string $column The column into which this data will be inserted
* @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) {
if (is_array($data) && !empty($data)) { if (is_array($data) && !empty($data)) {
return array_map( return array_map(
array(&$this, 'value'), array(&$this, 'value'),
$data, array_fill(0, count($data), $column), array_fill(0, count($data), $read) $data, array_fill(0, count($data), $column), array_fill(0, count($data), $safe)
); );
} elseif (is_object($data) && isset($data->type)) { } elseif (is_object($data) && isset($data->type)) {
if ($data->type == 'identifier') { if ($data->type == 'identifier') {
@ -181,11 +216,45 @@ class DboSource extends DataSource {
} }
} elseif (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) { } elseif (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) {
return $data; return $data;
} else { }
return null;
if ($data === null || (is_array($data) && empty($data))) {
return 'NULL';
}
if (empty($column)) {
$column = $this->introspectType($data);
}
switch ($column) {
case 'binary':
return $this->_connection->quote($data, PDO::PARAM_LOB);
break;
case 'boolean':
return $this->_connection->quote($this->boolean($data), PDO::PARAM_BOOL);
break;
case 'string':
case 'text':
return $this->_connection->quote($data, PDO::PARAM_STR);
default:
if ($data === '') {
return 'NULL';
}
if (is_float($data)) {
return sprintf('%F', $data);
}
if ((is_int($data) || $data === '0') || (
is_numeric($data) && strpos($data, ',') === false &&
$data[0] != '0' && strpos($data, 'e') === false)
) {
return $data;
}
return $this->_connection->quote($data);
break;
} }
} }
/** /**
* Returns an object to represent a database identifier in a query * Returns an object to represent a database identifier in a query
* *
@ -218,9 +287,9 @@ class DboSource extends DataSource {
* @param string $sql SQL statement * @param string $sql SQL statement
* @return boolean * @return boolean
*/ */
public function rawQuery($sql) { public function rawQuery($sql, $params = array()) {
$this->took = $this->error = $this->numRows = false; $this->took = $this->error = $this->numRows = false;
return $this->execute($sql); return $this->execute($sql, $params);
} }
/** /**
@ -230,28 +299,23 @@ class DboSource extends DataSource {
* *
* ### Options * ### Options
* *
* - stats - Collect meta data stats for this query. Stats include time take, rows affected,
* any errors, and number of rows returned. Defaults to `true`.
* - log - Whether or not the query should be logged to the memory log. * - log - Whether or not the query should be logged to the memory log.
* *
* @param string $sql * @param string $sql
* @param array $options * @param array $options
* @param array $params values to be bided to the query
* @return mixed Resource or object representing the result set, or false on failure * @return mixed Resource or object representing the result set, or false on failure
*/ */
public function execute($sql, $options = array()) { public function execute($sql, $options = array(), $params = array()) {
$defaults = array('stats' => true, 'log' => $this->fullDebug); $options = $options + array('log' => $this->fullDebug);
$options = array_merge($defaults, $options); $this->error = null;
$t = microtime(true); $t = microtime(true);
$this->_result = $this->_execute($sql); $this->_result = $this->_execute($sql, $params);
if ($options['stats']) {
$this->took = round((microtime(true) - $t) * 1000, 0);
$this->affected = $this->lastAffected();
$this->error = $this->lastError();
$this->numRows = $this->lastNumRows();
}
if ($options['log']) { if ($options['log']) {
$this->took = round((microtime(true) - $t) * 1000, 0);
$this->numRows = $this->affected = $this->lastAffected();
$this->logQuery($sql); $this->logQuery($sql);
} }
@ -262,6 +326,83 @@ class DboSource extends DataSource {
return $this->_result; return $this->_result;
} }
/**
* Executes given SQL statement.
*
* @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
* query returning no rows, suchs as a CREATE statement, false otherwise
*/
protected function _execute($sql, $params = array()) {
$sql = trim($sql);
if (preg_match('/^CREATE|^ALTER|^DROP/i', $sql)) {
$statements = array_filter(explode(';', $sql));
if (count($statements) > 1) {
$result = array_map(array($this, '_execute'), $statements);
return array_search(false, $result) === false;
}
}
try {
$query = $this->_connection->prepare($sql);
$query->setFetchMode(PDO::FETCH_LAZY);
if (!$query->execute($params)) {
$this->_results = $query;
$this->error = $this->lastError($query);
$query->closeCursor();
return false;
}
if (!$query->columnCount()) {
$query->closeCursor();
return true;
}
return $query;
} catch (PDOException $e) {
$this->_results = null;
$this->error = $e->getMessage();
return false;
}
}
/**
* Returns a formatted error message from previous database operation.
*
* @param PDOStatement $query the query to extract the error from if any
* @return string Error message with error number
*/
function lastError(PDOStatement $query = null) {
$error = $query->errorInfo();
if (empty($error[2])) {
return null;
}
return $error[1] . ': ' . $error[2];
}
/**
* 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($source = null) {
if ($this->hasResult()) {
return $this->_result->rowCount();
}
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($source = null) {
return $this->lastAffected($source);
}
/** /**
* DataSource Query abstraction * DataSource Query abstraction
* *
@ -352,8 +493,7 @@ class DboSource extends DataSource {
} else { } else {
$cache = true; $cache = true;
} }
$args[1] = array_map(array(&$this, 'value'), $args[1]); return $this->fetchAll($args[0], $args[1], array('cache' => $cache));
return $this->fetchAll(String::insert($args[0], $args[1]), $cache);
} }
} }
} }
@ -386,16 +526,31 @@ class DboSource extends DataSource {
* Returns an array of all result rows for a given SQL query. * Returns an array of all result rows for a given SQL query.
* Returns false if no rows matched. * Returns false if no rows matched.
* *
*
* ### Options
*
* - cache - Returns the cached version of the query, if exists and stores the result in cache
*
* @param string $sql SQL statement * @param string $sql SQL statement
* @param boolean $cache Enables returning/storing cached query results * @param array $params parameters to be bound as values for the SQL statement
* @param array $options additional options for the query.
* @return array Array of resultset rows, or false if no rows matched * @return array Array of resultset rows, or false if no rows matched
*/ */
public function fetchAll($sql, $cache = true, $modelName = null) { public function fetchAll($sql, $params = array(), $options = array()) {
if ($cache && ($cached = $this->getQueryCache($sql)) !== false) { if (is_string($options)) {
$options = array('modelName' => $options);
}
if (is_bool($params)) {
$options['cache'] = $params;
$params = array();
}
$defaults = array('cache' => true);
$options = $options + $defaults;
$cache = $options['cache'];
if ($cache && ($cached = $this->getQueryCache($sql, $params)) !== false) {
return $cached; return $cached;
} }
if ($result = $this->execute($sql, array(), $params)) {
if ($this->execute($sql)) {
$out = array(); $out = array();
$first = $this->fetchRow(); $first = $this->fetchRow();
@ -407,9 +562,10 @@ class DboSource extends DataSource {
$out[] = $item; $out[] = $item;
} }
if ($cache) { if (!is_bool($result) && $cache) {
$this->_writeQueryCache($sql, $out); $this->_writeQueryCache($sql, $out, $params);
} }
if (empty($out) && is_bool($this->_result)) { if (empty($out) && is_bool($this->_result)) {
return $this->_result; return $this->_result;
} }
@ -576,7 +732,7 @@ class DboSource extends DataSource {
* @return boolean True if the result is valid else false * @return boolean True if the result is valid else false
*/ */
public function hasResult() { public function hasResult() {
return is_resource($this->_result); return is_a($this->_result, 'PDOStatement');
} }
/** /**
@ -784,7 +940,7 @@ class DboSource extends DataSource {
foreach ($_associations as $type) { foreach ($_associations as $type) {
foreach ($model->{$type} as $assoc => $assocData) { foreach ($model->{$type} as $assoc => $assocData) {
$linkModel =& $model->{$assoc}; $linkModel = $model->{$assoc};
$external = isset($assocData['external']); $external = isset($assocData['external']);
if ($model->useDbConfig == $linkModel->useDbConfig) { if ($model->useDbConfig == $linkModel->useDbConfig) {
@ -795,9 +951,9 @@ class DboSource extends DataSource {
} }
} }
$query = $this->generateAssociationQuery($model, $null, null, null, null, $queryData, false, $null); $query = trim($this->generateAssociationQuery($model, $null, null, null, null, $queryData, false, $null));
$resultSet = $this->fetchAll($query, $model->cacheQueries, $model->alias); $resultSet = $this->fetchAll($query, $model->cacheQueries);
if ($resultSet === false) { if ($resultSet === false) {
$model->onError(); $model->onError();
@ -809,16 +965,16 @@ class DboSource extends DataSource {
if ($model->recursive > -1) { if ($model->recursive > -1) {
foreach ($_associations as $type) { foreach ($_associations as $type) {
foreach ($model->{$type} as $assoc => $assocData) { foreach ($model->{$type} as $assoc => $assocData) {
$linkModel =& $model->{$assoc}; $linkModel = $model->{$assoc};
if (empty($linkedModels[$type . '/' . $assoc])) { if (empty($linkedModels[$type . '/' . $assoc])) {
if ($model->useDbConfig == $linkModel->useDbConfig) { if ($model->useDbConfig == $linkModel->useDbConfig) {
$db =& $this; $db = $this;
} else { } else {
$db =& ConnectionManager::getDataSource($linkModel->useDbConfig); $db = ConnectionManager::getDataSource($linkModel->useDbConfig);
} }
} elseif ($model->recursive > 1 && ($type == 'belongsTo' || $type == 'hasOne')) { } elseif ($model->recursive > 1 && ($type == 'belongsTo' || $type == 'hasOne')) {
$db =& $this; $db = $this;
} }
if (isset($db) && method_exists($db, 'queryAssociation')) { if (isset($db) && method_exists($db, 'queryAssociation')) {
@ -924,14 +1080,14 @@ class DboSource extends DataSource {
if ($recursive > 0) { if ($recursive > 0) {
foreach ($linkModel->associations() as $type1) { foreach ($linkModel->associations() as $type1) {
foreach ($linkModel->{$type1} as $assoc1 => $assocData1) { foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
$deepModel =& $linkModel->{$assoc1}; $deepModel = $linkModel->{$assoc1};
$tmpStack = $stack; $tmpStack = $stack;
$tmpStack[] = $assoc1; $tmpStack[] = $assoc1;
if ($linkModel->useDbConfig === $deepModel->useDbConfig) { if ($linkModel->useDbConfig === $deepModel->useDbConfig) {
$db =& $this; $db = $this;
} else { } else {
$db =& ConnectionManager::getDataSource($deepModel->useDbConfig); $db = ConnectionManager::getDataSource($deepModel->useDbConfig);
} }
$db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack); $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
} }
@ -966,7 +1122,7 @@ class DboSource extends DataSource {
$q = $this->insertQueryData($query, null, $association, $assocData, $model, $linkModel, $stack); $q = $this->insertQueryData($query, null, $association, $assocData, $model, $linkModel, $stack);
if ($q != false) { if ($q != false) {
$fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias); $fetch = $this->fetchAll($q, $model->cacheQueries);
} else { } else {
$fetch = null; $fetch = null;
} }
@ -978,7 +1134,7 @@ class DboSource extends DataSource {
if ($type !== 'hasAndBelongsToMany') { if ($type !== 'hasAndBelongsToMany') {
$q = $this->insertQueryData($query, $resultSet[$i], $association, $assocData, $model, $linkModel, $stack); $q = $this->insertQueryData($query, $resultSet[$i], $association, $assocData, $model, $linkModel, $stack);
if ($q != false) { if ($q != false) {
$fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias); $fetch = $this->fetchAll($q, $model->cacheQueries);
} else { } else {
$fetch = null; $fetch = null;
} }
@ -993,15 +1149,15 @@ class DboSource extends DataSource {
if ($recursive > 0) { if ($recursive > 0) {
foreach ($linkModel->associations() as $type1) { foreach ($linkModel->associations() as $type1) {
foreach ($linkModel->{$type1} as $assoc1 => $assocData1) { foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
$deepModel =& $linkModel->{$assoc1}; $deepModel = $linkModel->{$assoc1};
if (($type1 === 'belongsTo') || ($deepModel->alias === $model->alias && $type === 'belongsTo') || ($deepModel->alias != $model->alias)) { if (($type1 === 'belongsTo') || ($deepModel->alias === $model->alias && $type === 'belongsTo') || ($deepModel->alias != $model->alias)) {
$tmpStack = $stack; $tmpStack = $stack;
$tmpStack[] = $assoc1; $tmpStack[] = $assoc1;
if ($linkModel->useDbConfig == $deepModel->useDbConfig) { if ($linkModel->useDbConfig == $deepModel->useDbConfig) {
$db =& $this; $db = $this;
} else { } else {
$db =& ConnectionManager::getDataSource($deepModel->useDbConfig); $db = ConnectionManager::getDataSource($deepModel->useDbConfig);
} }
$db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack); $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
} }
@ -1053,7 +1209,7 @@ class DboSource extends DataSource {
if (count($ids) > 1) { if (count($ids) > 1) {
$query = str_replace('= (', 'IN (', $query); $query = str_replace('= (', 'IN (', $query);
} }
return $this->fetchAll($query, $model->cacheQueries, $model->alias); return $this->fetchAll($query, $model->cacheQueries);
} }
/** /**
@ -1764,14 +1920,14 @@ class DboSource extends DataSource {
/** /**
* Begin a transaction * Begin a transaction
* *
* @param model $model
* @return boolean True on success, false on fail * @return boolean True on success, false on fail
* (i.e. if the database/model does not support transactions, * (i.e. if the database/model does not support transactions,
* or a transaction has not started). * or a transaction has not started).
*/ */
public function begin(&$model) { public function begin() {
if (parent::begin($model) && $this->execute($this->_commands['begin'])) { if ($this->_transactionStarted || $this->_connection->beginTransaction()) {
$this->_transactionStarted = true; $this->_transactionStarted = true;
$this->_transactionNesting++;
return true; return true;
} }
return false; return false;
@ -1780,14 +1936,18 @@ class DboSource extends DataSource {
/** /**
* Commit a transaction * Commit a transaction
* *
* @param model $model
* @return boolean True on success, false on fail * @return boolean True on success, false on fail
* (i.e. if the database/model does not support transactions, * (i.e. if the database/model does not support transactions,
* or a transaction has not started). * or a transaction has not started).
*/ */
public function commit(&$model) { public function commit() {
if (parent::commit($model) && $this->execute($this->_commands['commit'])) { if ($this->_transactionStarted) {
$this->_transactionStarted = false; $this->_transactionNesting--;
if ($this->_transactionNesting <= 0) {
$this->_transactionStarted = false;
$this->_transactionNesting = 0;
return $this->_connection->commit();
}
return true; return true;
} }
return false; return false;
@ -1796,19 +1956,29 @@ class DboSource extends DataSource {
/** /**
* Rollback a transaction * Rollback a transaction
* *
* @param model $model
* @return boolean True on success, false on fail * @return boolean True on success, false on fail
* (i.e. if the database/model does not support transactions, * (i.e. if the database/model does not support transactions,
* or a transaction has not started). * or a transaction has not started).
*/ */
public function rollback(&$model) { public function rollback() {
if (parent::rollback($model) && $this->execute($this->_commands['rollback'])) { if ($this->_transactionStarted && $this->_connection->rollBack()) {
$this->_transactionStarted = false; $this->_transactionStarted = false;
$this->_transactionNesting = 0;
return true; return true;
} }
return false; return false;
} }
/**
* Returns the ID generated from the previous INSERT operation.
*
* @param unknown_type $source
* @return in
*/
function lastInsertId($source = null) {
return $this->_connection->lastInsertId();
}
/** /**
* Creates a default set of conditions from the model if $conditions is null/empty. * Creates a default set of conditions from the model if $conditions is null/empty.
* If conditions are supplied then they will be returned. If a model doesn't exist and no conditions * If conditions are supplied then they will be returned. If a model doesn't exist and no conditions
@ -2524,7 +2694,7 @@ class DboSource extends DataSource {
* Translates between PHP boolean values and Database (faked) boolean values * Translates between PHP boolean values and Database (faked) boolean values
* *
* @param mixed $data Value to be translated * @param mixed $data Value to be translated
* @return mixed Converted boolean value * @return int Converted boolean value
*/ */
public function boolean($data) { public function boolean($data) {
if ($data === true || $data === false) { if ($data === true || $data === false) {
@ -2533,7 +2703,7 @@ class DboSource extends DataSource {
} }
return 0; return 0;
} else { } else {
return !empty($data); return (int) !empty($data);
} }
} }
@ -2546,13 +2716,18 @@ class DboSource extends DataSource {
*/ */
public function insertMulti($table, $fields, $values) { public function insertMulti($table, $fields, $values) {
$table = $this->fullTableName($table); $table = $this->fullTableName($table);
if (is_array($fields)) { $holder = implode(',', array_fill(0, count($fields), '?'));
$fields = implode(', ', array_map(array(&$this, 'name'), $fields)); $fields = implode(', ', array_map(array(&$this, 'name'), $fields));
}
$count = count($values); $count = count($values);
$sql = "INSERT INTO {$table} ({$fields}) VALUES ({$holder})";
$statement = $this->_connection->prepare($sql);
$this->begin();
for ($x = 0; $x < $count; $x++) { for ($x = 0; $x < $count; $x++) {
$this->query("INSERT INTO {$table} ({$fields}) VALUES {$values[$x]}"); $statement->execute($values[$x]);
$statement->closeCursor();
} }
return $this->commit();
} }
/** /**
@ -2867,11 +3042,12 @@ class DboSource extends DataSource {
* *
* @param string $sql SQL query * @param string $sql SQL query
* @param mixed $data result of $sql query * @param mixed $data result of $sql query
* @param array $params query params bound as values
* @return void * @return void
*/ */
protected function _writeQueryCache($sql, $data) { protected function _writeQueryCache($sql, $data, $params = array()) {
if (strpos(trim(strtolower($sql)), 'select') !== false) { if (preg_match('/^\s*select/i', $sql)) {
$this->_queryCache[$sql] = $data; $this->_queryCache[$sql][serialize($params)] = $data;
} }
} }
@ -2879,11 +3055,15 @@ class DboSource extends DataSource {
* Returns the result for a sql query if it is already cached * Returns the result for a sql query if it is already cached
* *
* @param string $sql SQL query * @param string $sql SQL query
* @param array $params query params bound as values
* @return mixed results for query if it is cached, false otherwise * @return mixed results for query if it is cached, false otherwise
*/ */
public function getQueryCache($sql = null) { public function getQueryCache($sql, $params = array()) {
if (isset($this->_queryCache[$sql]) && preg_match('/^\s*select/i', $sql)) { if (isset($this->_queryCache[$sql]) && preg_match('/^\s*select/i', $sql)) {
return $this->_queryCache[$sql]; $serialized = serialize($params);
if (isset($this->_queryCache[$sql][$serialized])) {
return $this->_queryCache[$sql][$serialized];
}
} }
return false; return false;
} }

View file

@ -904,9 +904,6 @@ class Model extends Object {
$dateFields = array('Y' => 'year', 'm' => 'month', 'd' => 'day', 'H' => 'hour', 'i' => 'min', 's' => 'sec'); $dateFields = array('Y' => 'year', 'm' => 'month', 'd' => 'day', 'H' => 'hour', 'i' => 'min', 's' => 'sec');
$timeFields = array('H' => 'hour', 'i' => 'min', 's' => 'sec'); $timeFields = array('H' => 'hour', 'i' => 'min', 's' => 'sec');
$db = $this->getDataSource();
$format = $db->columns[$type]['format'];
$date = array(); $date = array();
if (isset($data['hour']) && isset($data['meridian']) && $data['hour'] != 12 && 'pm' == $data['meridian']) { if (isset($data['hour']) && isset($data['meridian']) && $data['hour'] != 12 && 'pm' == $data['meridian']) {
@ -949,9 +946,13 @@ class Model extends Object {
} }
} }
} }
$date = str_replace(array_keys($date), array_values($date), $format);
$format = $this->getDataSource()->columns[$type]['format'];
$day = empty($date['Y']) ? null : $date['Y'] . '-' . $date['m'] . '-' . $date['d'] . ' ';
$hour = empty($date['H']) ? null : $date['H'] . ':' . $date['i'] . ':' . $date['s'];
$date = new DateTime($day . $hour);
if ($useNewDate && !empty($date)) { if ($useNewDate && !empty($date)) {
return $date; return $date->format($format);
} }
} }
return $data; return $data;
@ -1449,15 +1450,11 @@ class Model extends Object {
foreach ((array)$data as $row) { foreach ((array)$data as $row) {
if ((is_string($row) && (strlen($row) == 36 || strlen($row) == 16)) || is_numeric($row)) { if ((is_string($row) && (strlen($row) == 36 || strlen($row) == 16)) || is_numeric($row)) {
$values = array( $values = array($id, $row);
$db->value($id, $this->getColumnType($this->primaryKey)),
$db->value($row)
);
if ($isUUID && $primaryAdded) { if ($isUUID && $primaryAdded) {
$values[] = $db->value(String::uuid()); $values[] = String::uuid();
} }
$values = implode(',', $values); $newValues[] = $values;
$newValues[] = "({$values})";
unset($values); unset($values);
} elseif (isset($row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) { } elseif (isset($row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
$newData[] = $row; $newData[] = $row;
@ -1496,7 +1493,6 @@ class Model extends Object {
} }
if (!empty($newValues)) { if (!empty($newValues)) {
$fields = implode(',', $fields);
$db->insertMulti($this->{$join}, $fields, $newValues); $db->insertMulti($this->{$join}, $fields, $newValues);
} }
} }