Commit 752b5692 authored by Benjamin Eberlei's avatar Benjamin Eberlei

Merge pull request #447 from deeky666/fix-db2

Fix IBM DB2 implementation / ibm_db2 driver
parents f8b1a95d db2e0f37
# Upgrade to 2.5 # Upgrade to 2.5
No BC breaks yet. ## Support for pdo_ibm driver removed
The ``pdo_ibm`` driver is buggy and does not work well with Doctrine. Therefore it will no
longer be supported and has been removed from the ``Doctrine\DBAL\DriverManager`` drivers
map. It is highly encouraged to to use `ibm_db2` driver instead if you want to connect
to an IBM DB2 database as it is much more stable and secure.
If for some reason you have to utilize the ``pdo_ibm`` driver you can still use the `driverClass`
connection parameter to explicitly specify the ``Doctrine\DBAL\Driver\PDOIbm\Driver`` class.
However be aware that you are doing this at your own risk and it will not be guaranteed that
Doctrine will work as expected.
# Upgrade to 2.4 # Upgrade to 2.4
......
...@@ -33,6 +33,16 @@ class DB2Statement implements \IteratorAggregate, Statement ...@@ -33,6 +33,16 @@ class DB2Statement implements \IteratorAggregate, Statement
*/ */
private $_bindParam = array(); private $_bindParam = array();
/**
* @var string Name of the default class to instantiate when fetch mode is \PDO::FETCH_CLASS.
*/
private $defaultFetchClass = '\stdClass';
/**
* @var string Constructor arguments for the default class to instantiate when fetch mode is \PDO::FETCH_CLASS.
*/
private $defaultFetchClassCtorArgs = array();
/** /**
* @var integer * @var integer
*/ */
...@@ -166,6 +176,8 @@ class DB2Statement implements \IteratorAggregate, Statement ...@@ -166,6 +176,8 @@ class DB2Statement implements \IteratorAggregate, Statement
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
{ {
$this->_defaultFetchMode = $fetchMode; $this->_defaultFetchMode = $fetchMode;
$this->defaultFetchClass = $arg2 ? $arg2 : $this->defaultFetchClass;
$this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs;
return true; return true;
} }
...@@ -191,8 +203,27 @@ class DB2Statement implements \IteratorAggregate, Statement ...@@ -191,8 +203,27 @@ class DB2Statement implements \IteratorAggregate, Statement
return db2_fetch_both($this->_stmt); return db2_fetch_both($this->_stmt);
case \PDO::FETCH_ASSOC: case \PDO::FETCH_ASSOC:
return db2_fetch_assoc($this->_stmt); return db2_fetch_assoc($this->_stmt);
case \PDO::FETCH_CLASS:
$className = $this->defaultFetchClass;
$ctorArgs = $this->defaultFetchClassCtorArgs;
if (func_num_args() >= 2) {
$args = func_get_args();
$className = $args[1];
$ctorArgs = isset($args[2]) ? $args[2] : array();
}
$result = db2_fetch_object($this->_stmt);
if ($result instanceof \stdClass) {
$result = $this->castObject($result, $className, $ctorArgs);
}
return $result;
case \PDO::FETCH_NUM: case \PDO::FETCH_NUM:
return db2_fetch_array($this->_stmt); return db2_fetch_array($this->_stmt);
case PDO::FETCH_OBJ:
return db2_fetch_object($this->_stmt);
default: default:
throw new DB2Exception("Given Fetch-Style " . $fetchMode . " is not supported."); throw new DB2Exception("Given Fetch-Style " . $fetchMode . " is not supported.");
} }
...@@ -204,9 +235,23 @@ class DB2Statement implements \IteratorAggregate, Statement ...@@ -204,9 +235,23 @@ class DB2Statement implements \IteratorAggregate, Statement
public function fetchAll($fetchMode = null) public function fetchAll($fetchMode = null)
{ {
$rows = array(); $rows = array();
switch ($fetchMode) {
case \PDO::FETCH_CLASS:
while ($row = call_user_func_array(array($this, 'fetch'), func_get_args())) {
$rows[] = $row;
}
break;
case \PDO::FETCH_COLUMN:
while ($row = $this->fetchColumn()) {
$rows[] = $row;
}
break;
default:
while ($row = $this->fetch($fetchMode)) { while ($row = $this->fetch($fetchMode)) {
$rows[] = $row; $rows[] = $row;
} }
}
return $rows; return $rows;
} }
...@@ -231,4 +276,68 @@ class DB2Statement implements \IteratorAggregate, Statement ...@@ -231,4 +276,68 @@ class DB2Statement implements \IteratorAggregate, Statement
{ {
return (@db2_num_rows($this->_stmt))?:0; return (@db2_num_rows($this->_stmt))?:0;
} }
/**
* Casts a stdClass object to the given class name mapping its' properties.
*
* @param \stdClass $sourceObject Object to cast from.
* @param string|object $destinationClass Name of the class or class instance to cast to.
* @param array $ctorArgs Arguments to use for constructing the destination class instance.
*
* @return object
*
* @throws DB2Exception
*/
private function castObject(\stdClass $sourceObject, $destinationClass, array $ctorArgs = array())
{
if ( ! is_string($destinationClass)) {
if ( ! is_object($destinationClass)) {
throw new DB2Exception(sprintf(
'Destination class has to be of type string or object, %s given.', gettype($destinationClass)
));
}
} else {
$destinationClass = new \ReflectionClass($destinationClass);
$destinationClass = $destinationClass->newInstanceArgs($ctorArgs);
}
$sourceReflection = new \ReflectionObject($sourceObject);
$destinationClassReflection = new \ReflectionObject($destinationClass);
/** @var \ReflectionProperty[] $destinationProperties */
$destinationProperties = array_change_key_case($destinationClassReflection->getProperties(), \CASE_LOWER);
foreach ($sourceReflection->getProperties() as $sourceProperty) {
$sourceProperty->setAccessible(true);
$name = $sourceProperty->getName();
$value = $sourceProperty->getValue($sourceObject);
// Try to find a case-matching property.
if ($destinationClassReflection->hasProperty($name)) {
$destinationProperty = $destinationClassReflection->getProperty($name);
$destinationProperty->setAccessible(true);
$destinationProperty->setValue($destinationClass, $value);
continue;
}
$name = strtolower($name);
// Try to find a property without matching case.
// Fallback for the driver returning either all uppercase or all lowercase column names.
if (isset($destinationProperties[$name])) {
$destinationProperty = $destinationProperties[$name];
$destinationProperty->setAccessible(true);
$destinationProperty->setValue($destinationClass, $value);
continue;
}
$destinationClass->$name = $value;
}
return $destinationClass;
}
} }
...@@ -44,7 +44,6 @@ final class DriverManager ...@@ -44,7 +44,6 @@ final class DriverManager
'pdo_oci' => 'Doctrine\DBAL\Driver\PDOOracle\Driver', 'pdo_oci' => 'Doctrine\DBAL\Driver\PDOOracle\Driver',
'oci8' => 'Doctrine\DBAL\Driver\OCI8\Driver', 'oci8' => 'Doctrine\DBAL\Driver\OCI8\Driver',
'ibm_db2' => 'Doctrine\DBAL\Driver\IBMDB2\DB2Driver', 'ibm_db2' => 'Doctrine\DBAL\Driver\IBMDB2\DB2Driver',
'pdo_ibm' => 'Doctrine\DBAL\Driver\PDOIbm\Driver',
'pdo_sqlsrv' => 'Doctrine\DBAL\Driver\PDOSqlsrv\Driver', 'pdo_sqlsrv' => 'Doctrine\DBAL\Driver\PDOSqlsrv\Driver',
'mysqli' => 'Doctrine\DBAL\Driver\Mysqli\Driver', 'mysqli' => 'Doctrine\DBAL\Driver\Mysqli\Driver',
'drizzle_pdo_mysql' => 'Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver', 'drizzle_pdo_mysql' => 'Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver',
...@@ -73,7 +72,6 @@ final class DriverManager ...@@ -73,7 +72,6 @@ final class DriverManager
* pdo_pgsql * pdo_pgsql
* pdo_oci (unstable) * pdo_oci (unstable)
* pdo_sqlsrv * pdo_sqlsrv
* pdo_ibm (unstable)
* pdo_sqlsrv * pdo_sqlsrv
* mysqli * mysqli
* sqlanywhere * sqlanywhere
......
...@@ -30,7 +30,8 @@ class DB2Platform extends AbstractPlatform ...@@ -30,7 +30,8 @@ class DB2Platform extends AbstractPlatform
*/ */
public function getBlobTypeDeclarationSQL(array $field) public function getBlobTypeDeclarationSQL(array $field)
{ {
throw DBALException::notSupported(__METHOD__); // todo blob(n) with $field['length'];
return 'BLOB(1M)';
} }
/** /**
...@@ -47,6 +48,7 @@ class DB2Platform extends AbstractPlatform ...@@ -47,6 +48,7 @@ class DB2Platform extends AbstractPlatform
'varchar' => 'string', 'varchar' => 'string',
'character' => 'string', 'character' => 'string',
'clob' => 'text', 'clob' => 'text',
'blob' => 'blob',
'decimal' => 'decimal', 'decimal' => 'decimal',
'double' => 'float', 'double' => 'float',
'real' => 'float', 'real' => 'float',
...@@ -126,55 +128,111 @@ class DB2Platform extends AbstractPlatform ...@@ -126,55 +128,111 @@ class DB2Platform extends AbstractPlatform
} }
/** /**
* {@inheritDoc} * {@inheritdoc}
*/ */
public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) public function getBitAndComparisonExpression($value1, $value2)
{ {
if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) { return 'BITAND(' . $value1 . ', ' . $value2 . ')';
return "TIMESTAMP(0) WITH DEFAULT";
} }
return 'TIMESTAMP(0)'; /**
* {@inheritdoc}
*/
public function getBitOrComparisonExpression($value1, $value2)
{
return 'BITOR(' . $value1 . ', ' . $value2 . ')';
} }
/** /**
* {@inheritDoc} * {@inheritdoc}
*/ */
public function getDateTypeDeclarationSQL(array $fieldDeclaration) public function getDateAddDaysExpression($date, $days)
{ {
return 'DATE'; return $date . ' + ' . $days . ' days';
} }
/** /**
* {@inheritDoc} * {@inheritdoc}
*/ */
public function getTimeTypeDeclarationSQL(array $fieldDeclaration) public function getDateAddHourExpression($date, $hours)
{ {
return 'TIME'; return $date . ' + ' . $hours . ' hours';
}
/**
* {@inheritdoc}
*/
public function getDateAddMonthExpression($date, $months)
{
return $date . ' + ' . $months . ' months';
}
/**
* {@inheritdoc}
*/
public function getDateDiffExpression($date1, $date2)
{
return 'DAYS(' . $date1 . ') - DAYS(' . $date2 . ')';
}
/**
* {@inheritdoc}
*/
public function getDateSubDaysExpression($date, $days)
{
return $date . ' - ' . $days . ' days';
}
/**
* {@inheritdoc}
*/
public function getDateSubHourExpression($date, $hours)
{
return $date . ' - ' . $hours . ' hours';
}
/**
* {@inheritdoc}
*/
public function getDateSubMonthExpression($date, $months)
{
return $date . ' - ' . $months . ' months';
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function getListDatabasesSQL() public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
{ {
throw DBALException::notSupported(__METHOD__); if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) {
return "TIMESTAMP(0) WITH DEFAULT";
}
return 'TIMESTAMP(0)';
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function getListSequencesSQL($database) public function getDateTypeDeclarationSQL(array $fieldDeclaration)
{ {
throw DBALException::notSupported(__METHOD__); return 'DATE';
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function getListTableConstraintsSQL($table) public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
{
return 'TIME';
}
/**
* {@inheritdoc}
*/
public function getTruncateTableSQL($tableName, $cascade = false)
{ {
throw DBALException::notSupported(__METHOD__); return 'TRUNCATE ' . $tableName . ' IMMEDIATE';
} }
/** /**
...@@ -191,7 +249,11 @@ class DB2Platform extends AbstractPlatform ...@@ -191,7 +249,11 @@ class DB2Platform extends AbstractPlatform
{ {
return "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno, return "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno,
c.typename, c.default, c.nulls, c.length, c.scale, c.typename, c.default, c.nulls, c.length, c.scale,
c.identity, tc.type AS tabconsttype, k.colseq c.identity, tc.type AS tabconsttype, k.colseq,
CASE
WHEN c.generated = 'D' THEN 1
ELSE 0
END AS autoincrement
FROM syscat.columns c FROM syscat.columns c
LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc
ON (k.tabschema = tc.tabschema ON (k.tabschema = tc.tabschema
...@@ -211,14 +273,6 @@ class DB2Platform extends AbstractPlatform ...@@ -211,14 +273,6 @@ class DB2Platform extends AbstractPlatform
return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'"; return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'";
} }
/**
* {@inheritDoc}
*/
public function getListUsersSQL()
{
throw DBALException::notSupported(__METHOD__);
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
...@@ -232,7 +286,21 @@ class DB2Platform extends AbstractPlatform ...@@ -232,7 +286,21 @@ class DB2Platform extends AbstractPlatform
*/ */
public function getListTableIndexesSQL($table, $currentDatabase = null) public function getListTableIndexesSQL($table, $currentDatabase = null)
{ {
return "SELECT NAME, COLNAMES, UNIQUERULE FROM SYSIBM.SYSINDEXES WHERE TBNAME = UPPER('" . $table . "')"; return "SELECT idx.INDNAME AS key_name,
idxcol.COLNAME AS column_name,
CASE
WHEN idx.UNIQUERULE = 'P' THEN 1
ELSE 0
END AS primary,
CASE
WHEN idx.UNIQUERULE = 'D' THEN 1
ELSE 0
END AS non_unique
FROM SYSCAT.INDEXES AS idx
JOIN SYSCAT.INDEXCOLUSE AS idxcol
ON idx.INDSCHEMA = idxcol.INDSCHEMA AND idx.INDNAME = idxcol.INDNAME
WHERE idx.TABNAME = UPPER('" . $table . "')
ORDER BY idxcol.COLSEQ ASC";
} }
/** /**
...@@ -240,8 +308,31 @@ class DB2Platform extends AbstractPlatform ...@@ -240,8 +308,31 @@ class DB2Platform extends AbstractPlatform
*/ */
public function getListTableForeignKeysSQL($table) public function getListTableForeignKeysSQL($table)
{ {
return "SELECT TBNAME, RELNAME, REFTBNAME, DELETERULE, UPDATERULE, FKCOLNAMES, PKCOLNAMES ". return "SELECT fkcol.COLNAME AS local_column,
"FROM SYSIBM.SYSRELS WHERE TBNAME = UPPER('".$table."')"; fk.REFTABNAME AS foreign_table,
pkcol.COLNAME AS foreign_column,
fk.CONSTNAME AS index_name,
CASE
WHEN fk.UPDATERULE = 'R' THEN 'RESTRICT'
ELSE NULL
END AS on_update,
CASE
WHEN fk.DELETERULE = 'C' THEN 'CASCADE'
WHEN fk.DELETERULE = 'N' THEN 'SET NULL'
WHEN fk.DELETERULE = 'R' THEN 'RESTRICT'
ELSE NULL
END AS on_delete
FROM SYSCAT.REFERENCES AS fk
JOIN SYSCAT.KEYCOLUSE AS fkcol
ON fk.CONSTNAME = fkcol.CONSTNAME
AND fk.TABSCHEMA = fkcol.TABSCHEMA
AND fk.TABNAME = fkcol.TABNAME
JOIN SYSCAT.KEYCOLUSE AS pkcol
ON fk.REFKEYNAME = pkcol.CONSTNAME
AND fk.REFTABSCHEMA = pkcol.TABSCHEMA
AND fk.REFTABNAME = pkcol.TABNAME
WHERE fk.TABNAME = UPPER('" . $table . "')
ORDER BY fkcol.COLSEQ ASC";
} }
/** /**
...@@ -260,22 +351,6 @@ class DB2Platform extends AbstractPlatform ...@@ -260,22 +351,6 @@ class DB2Platform extends AbstractPlatform
return "DROP VIEW ".$name; return "DROP VIEW ".$name;
} }
/**
* {@inheritDoc}
*/
public function getDropSequenceSQL($sequence)
{
throw DBALException::notSupported(__METHOD__);
}
/**
* {@inheritDoc}
*/
public function getSequenceNextValSQL($sequenceName)
{
throw DBALException::notSupported(__METHOD__);
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
...@@ -289,7 +364,7 @@ class DB2Platform extends AbstractPlatform ...@@ -289,7 +364,7 @@ class DB2Platform extends AbstractPlatform
*/ */
public function getDropDatabaseSQL($database) public function getDropDatabaseSQL($database)
{ {
return "DROP DATABASE ".$database.";"; return "DROP DATABASE " . $database;
} }
/** /**
...@@ -313,7 +388,7 @@ class DB2Platform extends AbstractPlatform ...@@ -313,7 +388,7 @@ class DB2Platform extends AbstractPlatform
*/ */
public function getCurrentDateSQL() public function getCurrentDateSQL()
{ {
return 'VALUES CURRENT DATE'; return 'CURRENT DATE';
} }
/** /**
...@@ -321,7 +396,7 @@ class DB2Platform extends AbstractPlatform ...@@ -321,7 +396,7 @@ class DB2Platform extends AbstractPlatform
*/ */
public function getCurrentTimeSQL() public function getCurrentTimeSQL()
{ {
return 'VALUES CURRENT TIME'; return 'CURRENT TIME';
} }
/** /**
...@@ -329,7 +404,7 @@ class DB2Platform extends AbstractPlatform ...@@ -329,7 +404,7 @@ class DB2Platform extends AbstractPlatform
*/ */
public function getCurrentTimestampSQL() public function getCurrentTimestampSQL()
{ {
return "VALUES CURRENT TIMESTAMP"; return "CURRENT TIMESTAMP";
} }
/** /**
...@@ -373,7 +448,18 @@ class DB2Platform extends AbstractPlatform ...@@ -373,7 +448,18 @@ class DB2Platform extends AbstractPlatform
continue; continue;
} }
$queryParts[] = 'ADD COLUMN ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); $columnDef = $column->toArray();
$queryPart = 'ADD COLUMN ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnDef);
// Adding non-nullable columns to a table requires a default value to be specified.
if ( ! empty($columnDef['notnull']) &&
! isset($columnDef['default']) &&
empty($columnDef['autoincrement'])
) {
$queryPart .= ' WITH DEFAULT';
}
$queryParts[] = $queryPart;
} }
foreach ($diff->removedColumns as $column) { foreach ($diff->removedColumns as $column) {
...@@ -400,7 +486,7 @@ class DB2Platform extends AbstractPlatform ...@@ -400,7 +486,7 @@ class DB2Platform extends AbstractPlatform
continue; continue;
} }
$queryParts[] = 'RENAME ' . $oldColumnName . ' TO ' . $column->getQuotedName($this); $queryParts[] = 'RENAME COLUMN ' . $oldColumnName . ' TO ' . $column->getQuotedName($this);
} }
$tableSql = array(); $tableSql = array();
...@@ -410,10 +496,19 @@ class DB2Platform extends AbstractPlatform ...@@ -410,10 +496,19 @@ class DB2Platform extends AbstractPlatform
$sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(" ", $queryParts); $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(" ", $queryParts);
} }
$sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff)); // Some table alteration operations require a table reorganization.
if ( ! empty($diff->removedColumns) || ! empty($diff->changedColumns)) {
$sql[] = "CALL SYSPROC.ADMIN_CMD ('REORG TABLE " . $diff->name . "')";
}
$sql = array_merge(
$this->getPreAlterTableIndexForeignKeySQL($diff),
$sql,
$this->getPostAlterTableIndexForeignKeySQL($diff)
);
if ($diff->newName !== false) { if ($diff->newName !== false) {
$sql[] = 'RENAME TABLE TO ' . $diff->newName; $sql[] = 'RENAME TABLE ' . $diff->name . ' TO ' . $diff->newName;
} }
} }
...@@ -423,23 +518,46 @@ class DB2Platform extends AbstractPlatform ...@@ -423,23 +518,46 @@ class DB2Platform extends AbstractPlatform
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function getDefaultValueDeclarationSQL($field) protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
{ {
if (isset($field['notnull']) && $field['notnull'] && !isset($field['default'])) { $sql = array();
if (in_array((string)$field['type'], array("Integer", "BigInteger", "SmallInteger"))) { $table = $diff->name;
$field['default'] = 0;
} else if((string)$field['type'] == "DateTime") { foreach ($diff->removedIndexes as $remKey => $remIndex) {
$field['default'] = "00-00-00 00:00:00"; foreach ($diff->addedIndexes as $addKey => $addIndex) {
} else if ((string)$field['type'] == "Date") { if ($remIndex->getColumns() == $addIndex->getColumns()) {
$field['default'] = "00-00-00"; if ($remIndex->isPrimary()) {
} else if((string)$field['type'] == "Time") { $sql[] = 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY';
$field['default'] = "00:00:00"; } elseif ($remIndex->isUnique()) {
$sql[] = 'ALTER TABLE ' . $table . ' DROP UNIQUE ' . $remIndex->getQuotedName($this);
} else { } else {
$field['default'] = ''; $sql[] = $this->getDropIndexSQL($remIndex, $table);
}
$sql[] = $this->getCreateIndexSQL($addIndex, $table);
unset($diff->removedIndexes[$remKey]);
unset($diff->addedIndexes[$addKey]);
break;
} }
} }
}
$sql = array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff));
return $sql;
}
/**
* {@inheritDoc}
*/
public function getDefaultValueDeclarationSQL($field)
{
if ( ! empty($field['autoincrement'])) {
return '';
}
unset($field['default']); // @todo this needs fixing
if (isset($field['version']) && $field['version']) { if (isset($field['version']) && $field['version']) {
if ((string)$field['type'] != "DateTime") { if ((string)$field['type'] != "DateTime") {
$field['default'] = "1"; $field['default'] = "1";
......
...@@ -37,6 +37,7 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -37,6 +37,7 @@ class Connection extends \Doctrine\DBAL\Connection
const PORTABILITY_EMPTY_TO_NULL = 4; const PORTABILITY_EMPTY_TO_NULL = 4;
const PORTABILITY_FIX_CASE = 8; const PORTABILITY_FIX_CASE = 8;
const PORTABILITY_DB2 = 13;
const PORTABILITY_ORACLE = 9; const PORTABILITY_ORACLE = 9;
const PORTABILITY_POSTGRESQL = 13; const PORTABILITY_POSTGRESQL = 13;
const PORTABILITY_SQLITE = 13; const PORTABILITY_SQLITE = 13;
...@@ -76,6 +77,8 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -76,6 +77,8 @@ class Connection extends \Doctrine\DBAL\Connection
$params['portability'] = self::PORTABILITY_SQLANYWHERE; $params['portability'] = self::PORTABILITY_SQLANYWHERE;
} else if ($this->_platform->getName() === 'sqlsrv') { } else if ($this->_platform->getName() === 'sqlsrv') {
$params['portability'] = $params['portabililty'] & self::PORTABILITY_SQLSRV; $params['portability'] = $params['portabililty'] & self::PORTABILITY_SQLSRV;
} elseif ($this->_platform->getName() === 'db2') {
$params['portability'] = self::PORTABILITY_DB2;
} else { } else {
$params['portability'] = $params['portability'] & self::PORTABILITY_OTHERVENDORS; $params['portability'] = $params['portability'] & self::PORTABILITY_OTHERVENDORS;
} }
......
...@@ -19,9 +19,6 @@ ...@@ -19,9 +19,6 @@
namespace Doctrine\DBAL\Schema; namespace Doctrine\DBAL\Schema;
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
use Doctrine\DBAL\Events;
/** /**
* IBM Db2 Schema Manager. * IBM Db2 Schema Manager.
* *
...@@ -60,6 +57,12 @@ class DB2SchemaManager extends AbstractSchemaManager ...@@ -60,6 +57,12 @@ class DB2SchemaManager extends AbstractSchemaManager
$scale = false; $scale = false;
$precision = false; $precision = false;
$default = null;
if (null !== $tableColumn['default'] && 'NULL' != $tableColumn['default']) {
$default = trim($tableColumn['default'], "'");
}
$type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']); $type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']);
switch (strtolower($tableColumn['typename'])) { switch (strtolower($tableColumn['typename'])) {
...@@ -86,7 +89,8 @@ class DB2SchemaManager extends AbstractSchemaManager ...@@ -86,7 +89,8 @@ class DB2SchemaManager extends AbstractSchemaManager
'length' => $length, 'length' => $length,
'unsigned' => (bool)$unsigned, 'unsigned' => (bool)$unsigned,
'fixed' => (bool)$fixed, 'fixed' => (bool)$fixed,
'default' => ($tableColumn['default'] == "NULL") ? null : $tableColumn['default'], 'default' => $default,
'autoincrement' => (boolean) $tableColumn['autoincrement'],
'notnull' => (bool) ($tableColumn['nulls'] == 'N'), 'notnull' => (bool) ($tableColumn['nulls'] == 'N'),
'scale' => null, 'scale' => null,
'precision' => null, 'precision' => null,
...@@ -118,46 +122,14 @@ class DB2SchemaManager extends AbstractSchemaManager ...@@ -118,46 +122,14 @@ class DB2SchemaManager extends AbstractSchemaManager
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected function _getPortableTableIndexesList($tableIndexes, $tableName=null) protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
{ {
$eventManager = $this->_platform->getEventManager(); foreach ($tableIndexRows as &$tableIndexRow) {
$tableIndexRow = array_change_key_case($tableIndexRow, \CASE_LOWER);
$indexes = array(); $tableIndexRow['primary'] = (boolean) $tableIndexRow['primary'];
foreach($tableIndexes as $indexKey => $data) {
$data = array_change_key_case($data, \CASE_LOWER);
$unique = ($data['uniquerule'] == "D") ? false : true;
$primary = ($data['uniquerule'] == "P");
$indexName = strtolower($data['name']);
$data = array(
'name' => $indexName,
'columns' => explode("+", ltrim($data['colnames'], '+')),
'unique' => $unique,
'primary' => $primary
);
$index = null;
$defaultPrevented = false;
if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
$eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
$eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
$defaultPrevented = $eventArgs->isDefaultPrevented();
$index = $eventArgs->getIndex();
} }
if ( ! $defaultPrevented) { return parent::_getPortableTableIndexesList($tableIndexRows, $tableName);
$index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']);
}
if ($index) {
$indexes[$indexKey] = $index;
}
}
return $indexes;
} }
/** /**
...@@ -165,21 +137,43 @@ class DB2SchemaManager extends AbstractSchemaManager ...@@ -165,21 +137,43 @@ class DB2SchemaManager extends AbstractSchemaManager
*/ */
protected function _getPortableTableForeignKeyDefinition($tableForeignKey) protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
{ {
$tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER);
$tableForeignKey['deleterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['deleterule']);
$tableForeignKey['updaterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['updaterule']);
return new ForeignKeyConstraint( return new ForeignKeyConstraint(
array_map('trim', (array)$tableForeignKey['fkcolnames']), $tableForeignKey['local_columns'],
$tableForeignKey['reftbname'], $tableForeignKey['foreign_table'],
array_map('trim', (array)$tableForeignKey['pkcolnames']), $tableForeignKey['foreign_columns'],
$tableForeignKey['relname'], $tableForeignKey['name'],
array( $tableForeignKey['options']
'onUpdate' => $tableForeignKey['updaterule'], );
'onDelete' => $tableForeignKey['deleterule'], }
/**
* {@inheritdoc}
*/
protected function _getPortableTableForeignKeysList($tableForeignKeys)
{
$foreignKeys = array();
foreach ($tableForeignKeys as $tableForeignKey) {
$tableForeignKey = array_change_key_case($tableForeignKey, \CASE_LOWER);
if (!isset($foreignKeys[$tableForeignKey['index_name']])) {
$foreignKeys[$tableForeignKey['index_name']] = array(
'local_columns' => array($tableForeignKey['local_column']),
'foreign_table' => $tableForeignKey['foreign_table'],
'foreign_columns' => array($tableForeignKey['foreign_column']),
'name' => $tableForeignKey['index_name'],
'options' => array(
'onUpdate' => $tableForeignKey['on_update'],
'onDelete' => $tableForeignKey['on_delete'],
) )
); );
} else {
$foreignKeys[$tableForeignKey['index_name']]['local_columns'][] = $tableForeignKey['local_column'];
$foreignKeys[$tableForeignKey['index_name']]['foreign_columns'][] = $tableForeignKey['foreign_column'];
}
}
return parent::_getPortableTableForeignKeysList($foreignKeys);
} }
/** /**
......
...@@ -273,12 +273,12 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest ...@@ -273,12 +273,12 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertTrue($tableIndexes['primary']->isUnique()); $this->assertTrue($tableIndexes['primary']->isUnique());
$this->assertTrue($tableIndexes['primary']->isPrimary()); $this->assertTrue($tableIndexes['primary']->isPrimary());
$this->assertEquals('test_index_name', $tableIndexes['test_index_name']->getName()); $this->assertEquals('test_index_name', strtolower($tableIndexes['test_index_name']->getName()));
$this->assertEquals(array('test'), array_map('strtolower', $tableIndexes['test_index_name']->getColumns())); $this->assertEquals(array('test'), array_map('strtolower', $tableIndexes['test_index_name']->getColumns()));
$this->assertTrue($tableIndexes['test_index_name']->isUnique()); $this->assertTrue($tableIndexes['test_index_name']->isUnique());
$this->assertFalse($tableIndexes['test_index_name']->isPrimary()); $this->assertFalse($tableIndexes['test_index_name']->isPrimary());
$this->assertEquals('test_composite_idx', $tableIndexes['test_composite_idx']->getName()); $this->assertEquals('test_composite_idx', strtolower($tableIndexes['test_composite_idx']->getName()));
$this->assertEquals(array('id', 'test'), array_map('strtolower', $tableIndexes['test_composite_idx']->getColumns())); $this->assertEquals(array('id', 'test'), array_map('strtolower', $tableIndexes['test_composite_idx']->getColumns()));
$this->assertFalse($tableIndexes['test_composite_idx']->isUnique()); $this->assertFalse($tableIndexes['test_composite_idx']->isUnique());
$this->assertFalse($tableIndexes['test_composite_idx']->isPrimary()); $this->assertFalse($tableIndexes['test_composite_idx']->isPrimary());
......
<?php
namespace Doctrine\Tests\DBAL\Platforms;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\DB2Platform;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
class DB2PlatformTest extends AbstractPlatformTestCase
{
/**
* @var \Doctrine\DBAL\Platforms\DB2Platform
*/
protected $_platform;
public function createPlatform()
{
return new DB2Platform();
}
public function getGenerateAlterTableSql()
{
return array(
"ALTER TABLE mytable ADD COLUMN quota INTEGER DEFAULT NULL DROP COLUMN foo ALTER bar baz VARCHAR(255) DEFAULT 'def' NOT NULL ALTER bloo bloo SMALLINT DEFAULT '0' NOT NULL",
"CALL SYSPROC.ADMIN_CMD ('REORG TABLE mytable')",
'RENAME TABLE mytable TO userlist',
);
}
public function getGenerateForeignKeySql()
{
return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)';
}
public function getGenerateIndexSql()
{
return 'CREATE INDEX my_idx ON mytable (user_name, last_login)';
}
public function getGenerateTableSql()
{
return 'CREATE TABLE test (id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))';
}
public function getGenerateTableWithMultiColumnUniqueIndexSql()
{
return array(
'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL)',
'CREATE UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA ON test (foo, bar)'
);
}
public function getGenerateUniqueIndexSql()
{
return 'CREATE UNIQUE INDEX index_name ON test (test, test2)';
}
protected function getQuotedColumnInForeignKeySQL()
{
return array(
'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, "bar" VARCHAR(255) NOT NULL)',
'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES "foreign" ("create", bar, "foo-bar")',
'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES foo ("create", bar, "foo-bar")',
'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ("create", foo, "bar") REFERENCES "foo-bar" ("create", bar, "foo-bar")',
);
}
protected function getQuotedColumnInIndexSQL()
{
return array(
'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL)',
'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")'
);
}
protected function getQuotedColumnInPrimaryKeySQL()
{
return array(
'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, PRIMARY KEY("create"))'
);
}
protected function getBitAndComparisonExpressionSql($value1, $value2)
{
return 'BITAND(' . $value1 . ', ' . $value2 . ')';
}
protected function getBitOrComparisonExpressionSql($value1, $value2)
{
return 'BITOR(' . $value1 . ', ' . $value2 . ')';
}
public function getCreateTableColumnCommentsSQL()
{
return array(
"CREATE TABLE test (id INTEGER NOT NULL, PRIMARY KEY(id))",
);
}
public function getAlterTableColumnCommentsSQL()
{
return array(
"ALTER TABLE mytable ADD COLUMN quota INTEGER NOT NULL WITH DEFAULT ALTER foo foo VARCHAR(255) NOT NULL ALTER bar baz VARCHAR(255) NOT NULL",
"CALL SYSPROC.ADMIN_CMD ('REORG TABLE mytable')"
);
}
public function getCreateTableColumnTypeCommentsSQL()
{
return array(
'CREATE TABLE test (id INTEGER NOT NULL, "data" CLOB(1M) NOT NULL, PRIMARY KEY(id))',
);
}
public function testHasCorrectPlatformName()
{
$this->assertEquals('db2', $this->_platform->getName());
}
public function testGeneratesCreateTableSQLWithCommonIndexes()
{
$table = new Table('test');
$table->addColumn('id', 'integer');
$table->addColumn('name', 'string', array('length' => 50));
$table->setPrimaryKey(array('id'));
$table->addIndex(array('name'));
$table->addIndex(array('id', 'name'), 'composite_idx');
$this->assertEquals(
array(
'CREATE TABLE test (id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id))',
'CREATE INDEX IDX_D87F7E0C5E237E06 ON test (name)',
'CREATE INDEX composite_idx ON test (id, name)'
),
$this->_platform->getCreateTableSQL($table)
);
}
public function testGeneratesCreateTableSQLWithForeignKeyConstraints()
{
$table = new Table('test');
$table->addColumn('id', 'integer');
$table->addColumn('fk_1', 'integer');
$table->addColumn('fk_2', 'integer');
$table->setPrimaryKey(array('id'));
$table->addForeignKeyConstraint('foreign_table', array('fk_1', 'fk_2'), array('pk_1', 'pk_2'));
$table->addForeignKeyConstraint(
'foreign_table2',
array('fk_1', 'fk_2'),
array('pk_1', 'pk_2'),
array(),
'named_fk'
);
$this->assertEquals(
array(
'CREATE TABLE test (id INTEGER NOT NULL, fk_1 INTEGER NOT NULL, fk_2 INTEGER NOT NULL)',
'ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C177612A38E7F4319 FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table (pk_1, pk_2)',
'ALTER TABLE test ADD CONSTRAINT named_fk FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table2 (pk_1, pk_2)',
),
$this->_platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS)
);
}
public function testGeneratesCreateTableSQLWithCheckConstraints()
{
$table = new Table('test');
$table->addColumn('id', 'integer');
$table->addColumn('check_max', 'integer', array('platformOptions' => array('max' => 10)));
$table->addColumn('check_min', 'integer', array('platformOptions' => array('min' => 10)));
$table->setPrimaryKey(array('id'));
$this->assertEquals(
array(
'CREATE TABLE test (id INTEGER NOT NULL, check_max INTEGER NOT NULL, check_min INTEGER NOT NULL, PRIMARY KEY(id), CHECK (check_max <= 10), CHECK (check_min >= 10))'
),
$this->_platform->getCreateTableSQL($table)
);
}
public function testGeneratesColumnTypesDeclarationSQL()
{
$fullColumnDef = array(
'length' => 10,
'fixed' => true,
'unsigned' => true,
'autoincrement' => true
);
$this->assertEquals('VARCHAR(255)', $this->_platform->getVarcharTypeDeclarationSQL(array()));
$this->assertEquals('VARCHAR(10)', $this->_platform->getVarcharTypeDeclarationSQL(array('length' => 10)));
$this->assertEquals('CHAR(255)', $this->_platform->getVarcharTypeDeclarationSQL(array('fixed' => true)));
$this->assertEquals('CHAR(10)', $this->_platform->getVarcharTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('SMALLINT', $this->_platform->getSmallIntTypeDeclarationSQL(array()));
$this->assertEquals('SMALLINT', $this->_platform->getSmallIntTypeDeclarationSQL(array(
'unsigned' => true
)));
$this->assertEquals('SMALLINT GENERATED BY DEFAULT AS IDENTITY', $this->_platform->getSmallIntTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('INTEGER', $this->_platform->getIntegerTypeDeclarationSQL(array()));
$this->assertEquals('INTEGER', $this->_platform->getIntegerTypeDeclarationSQL(array(
'unsigned' => true
)));
$this->assertEquals('INTEGER GENERATED BY DEFAULT AS IDENTITY', $this->_platform->getIntegerTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('BIGINT', $this->_platform->getBigIntTypeDeclarationSQL(array()));
$this->assertEquals('BIGINT', $this->_platform->getBigIntTypeDeclarationSQL(array(
'unsigned' => true
)));
$this->assertEquals('BIGINT GENERATED BY DEFAULT AS IDENTITY', $this->_platform->getBigIntTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('BLOB(1M)', $this->_platform->getBlobTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('SMALLINT', $this->_platform->getBooleanTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('CLOB(1M)', $this->_platform->getClobTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('DATE', $this->_platform->getDateTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('TIMESTAMP(0) WITH DEFAULT', $this->_platform->getDateTimeTypeDeclarationSQL(array('version' => true)));
$this->assertEquals('TIMESTAMP(0)', $this->_platform->getDateTimeTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('TIME', $this->_platform->getTimeTypeDeclarationSQL($fullColumnDef));
}
public function testInitializesDoctrineTypeMappings()
{
$this->_platform->initializeDoctrineTypeMappings();
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('smallint'));
$this->assertSame('smallint', $this->_platform->getDoctrineTypeMapping('smallint'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('bigint'));
$this->assertSame('bigint', $this->_platform->getDoctrineTypeMapping('bigint'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('integer'));
$this->assertSame('integer', $this->_platform->getDoctrineTypeMapping('integer'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('time'));
$this->assertSame('time', $this->_platform->getDoctrineTypeMapping('time'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('date'));
$this->assertSame('date', $this->_platform->getDoctrineTypeMapping('date'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('varchar'));
$this->assertSame('string', $this->_platform->getDoctrineTypeMapping('varchar'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('character'));
$this->assertSame('string', $this->_platform->getDoctrineTypeMapping('character'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('clob'));
$this->assertSame('text', $this->_platform->getDoctrineTypeMapping('clob'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('blob'));
$this->assertSame('blob', $this->_platform->getDoctrineTypeMapping('blob'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('decimal'));
$this->assertSame('decimal', $this->_platform->getDoctrineTypeMapping('decimal'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('double'));
$this->assertSame('float', $this->_platform->getDoctrineTypeMapping('double'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('real'));
$this->assertSame('float', $this->_platform->getDoctrineTypeMapping('real'));
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('timestamp'));
$this->assertSame('datetime', $this->_platform->getDoctrineTypeMapping('timestamp'));
}
public function testGeneratesDDLSnippets()
{
$this->assertEquals("CREATE DATABASE foobar", $this->_platform->getCreateDatabaseSQL('foobar'));
$this->assertEquals("DROP DATABASE foobar", $this->_platform->getDropDatabaseSQL('foobar'));
$this->assertEquals('DECLARE GLOBAL TEMPORARY TABLE', $this->_platform->getCreateTemporaryTableSnippetSQL());
$this->assertEquals('TRUNCATE foobar IMMEDIATE', $this->_platform->getTruncateTableSQL('foobar'));
$this->assertEquals('TRUNCATE foobar IMMEDIATE', $this->_platform->getTruncateTableSQL('foobar'), true);
$viewSql = 'SELECT * FROM footable';
$this->assertEquals('CREATE VIEW fooview AS ' . $viewSql, $this->_platform->getCreateViewSQL('fooview', $viewSql));
$this->assertEquals('DROP VIEW fooview', $this->_platform->getDropViewSQL('fooview'));
}
public function testGeneratesCreateUnnamedPrimaryKeySQL()
{
$this->assertEquals(
'ALTER TABLE foo ADD PRIMARY KEY (a, b)',
$this->_platform->getCreatePrimaryKeySQL(
new Index('any_pk_name', array('a', 'b'), true, true),
'foo'
)
);
}
public function testGeneratesSQLSnippets()
{
$this->assertEquals('CURRENT DATE', $this->_platform->getCurrentDateSQL());
$this->assertEquals('CURRENT TIME', $this->_platform->getCurrentTimeSQL());
$this->assertEquals('CURRENT TIMESTAMP', $this->_platform->getCurrentTimestampSQL());
$this->assertEquals("'1987/05/02' + 4 days", $this->_platform->getDateAddDaysExpression("'1987/05/02'", 4));
$this->assertEquals("'1987/05/02' + 12 hours", $this->_platform->getDateAddHourExpression("'1987/05/02'", 12));
$this->assertEquals("'1987/05/02' + 102 months", $this->_platform->getDateAddMonthExpression("'1987/05/02'", 102));
$this->assertEquals("DAYS('1987/05/02') - DAYS('1987/04/01')", $this->_platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'"));
$this->assertEquals("'1987/05/02' - 4 days", $this->_platform->getDateSubDaysExpression("'1987/05/02'", 4));
$this->assertEquals("'1987/05/02' - 12 hours", $this->_platform->getDateSubHourExpression("'1987/05/02'", 12));
$this->assertEquals("'1987/05/02' - 102 months", $this->_platform->getDateSubMonthExpression("'1987/05/02'", 102));
$this->assertEquals(' WITH RR USE AND KEEP UPDATE LOCKS', $this->_platform->getForUpdateSQL());
$this->assertEquals('LOCATE(substring_column, string_column)', $this->_platform->getLocateExpression('string_column', 'substring_column'));
$this->assertEquals('LOCATE(substring_column, string_column)', $this->_platform->getLocateExpression('string_column', 'substring_column'));
$this->assertEquals('LOCATE(substring_column, string_column, 1)', $this->_platform->getLocateExpression('string_column', 'substring_column', 1));
$this->assertEquals('SUBSTR(column, 5)', $this->_platform->getSubstringExpression('column', 5));
$this->assertEquals('SUBSTR(column, 5, 2)', $this->_platform->getSubstringExpression('column', 5, 2));
}
public function testModifiesLimitQuery()
{
$this->assertEquals(
'SELECT * FROM user',
$this->_platform->modifyLimitQuery('SELECT * FROM user', null, null)
);
$this->assertEquals(
'SELECT db22.* FROM (SELECT ROW_NUMBER() OVER() AS DC_ROWNUM, db21.* FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM BETWEEN 1 AND 10',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0)
);
$this->assertEquals(
'SELECT db22.* FROM (SELECT ROW_NUMBER() OVER() AS DC_ROWNUM, db21.* FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM BETWEEN 1 AND 10',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 10)
);
$this->assertEquals(
'SELECT db22.* FROM (SELECT ROW_NUMBER() OVER() AS DC_ROWNUM, db21.* FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM BETWEEN 6 AND 15',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 5)
);
$this->assertEquals(
'SELECT db22.* FROM (SELECT ROW_NUMBER() OVER() AS DC_ROWNUM, db21.* FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM BETWEEN 6 AND 5',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 0, 5)
);
}
public function testPrefersIdentityColumns()
{
$this->assertTrue($this->_platform->prefersIdentityColumns());
}
public function testSupportsIdentityColumns()
{
$this->assertTrue($this->_platform->supportsIdentityColumns());
}
public function testDoesNotSupportSavePoints()
{
$this->assertFalse($this->_platform->supportsSavepoints());
}
public function testDoesNotSupportReleasePoints()
{
$this->assertFalse($this->_platform->supportsReleaseSavepoints());
}
public function testDoesNotSupportCreateDropDatabase()
{
$this->assertFalse($this->_platform->supportsCreateDropDatabase());
}
public function testReturnsSQLResultCasing()
{
$this->assertSame('COL', $this->_platform->getSQLResultCasing('cOl'));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment