Commit 8aa45b5e authored by Benjamin Eberlei's avatar Benjamin Eberlei

Merge branch 'master' of github.com:doctrine/dbal

parents 9cd6df38 fdb0f8b1
......@@ -68,6 +68,9 @@ class Driver implements \Doctrine\DBAL\Driver
if (isset($params['unix_socket'])) {
$dsn .= 'unix_socket=' . $params['unix_socket'] . ';';
}
if (isset($params['charset'])) {
$dsn .= 'charset=' . $params['charset'] . ';';
}
return $dsn;
}
......
......@@ -719,6 +719,68 @@ abstract class AbstractPlatform
return 'COS(' . $value . ')';
}
/**
* Calculate the difference in days between the two passed dates.
*
* Computes diff = date1 - date2
*
* @param string $date1
* @param string $date2
* @return string
*/
public function getDateDiffExpression($date1, $date2)
{
throw DBALException::notSupported(__METHOD__);
}
/**
* Add the number of given days to a date.
*
* @param string $date
* @param int $days
* @return string
*/
public function getDateAddDaysExpression($date, $days)
{
throw DBALException::notSupported(__METHOD__);
}
/**
* Substract the number of given days to a date.
*
* @param string $date
* @param int $days
* @return string
*/
public function getDateSubDaysExpression($date, $days)
{
throw DBALException::notSupported(__METHOD__);
}
/**
* Add the number of given months to a date.
*
* @param string $date
* @param int $months
* @return string
*/
public function getDateAddMonthExpression($date, $months)
{
throw DBALException::notSupported(__METHOD__);
}
/**
* Substract the number of given months to a date.
*
* @param string $date
* @param int $months
* @return string
*/
public function getDateSubMonthExpression($date, $months)
{
throw DBALException::notSupported(__METHOD__);
}
public function getForUpdateSQL()
{
return 'FOR UPDATE';
......@@ -2074,13 +2136,40 @@ abstract class AbstractPlatform
return 'H:i:s';
}
public function modifyLimitQuery($query, $limit, $offset = null)
/**
* Modify limit query
*
* @param string $query
* @param int $limit
* @param int $offset
* @return string
*/
final public function modifyLimitQuery($query, $limit, $offset = null)
{
if ( $limit !== null) {
$limit = (int)$limit;
}
if ( $offset !== null) {
$offset = (int)$offset;
}
return $this->doModifyLimitQuery($query, $limit, $offset);
}
/**
* @param string $query
* @param int $limit
* @param int $offset
* @return string
*/
protected function doModifyLimitQuery($query, $limit, $offset)
{
if ( ! is_null($limit)) {
if ( $limit !== null) {
$query .= ' LIMIT ' . $limit;
}
if ( ! is_null($offset)) {
if ( $offset !== null) {
$query .= ' OFFSET ' . $offset;
}
......
......@@ -453,7 +453,7 @@ class DB2Platform extends AbstractPlatform
return "SESSION." . $tableName;
}
public function modifyLimitQuery($query, $limit, $offset = null)
protected function doModifyLimitQuery($query, $limit, $offset = null)
{
if ($limit === null && $offset === null) {
return $query;
......
......@@ -583,14 +583,14 @@ class MsSqlPlatform extends AbstractPlatform
* @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
* @return string
*/
public function modifyLimitQuery($query, $limit, $offset = null)
protected function doModifyLimitQuery($query, $limit, $offset = null)
{
if ($limit > 0) {
$count = intval($limit);
$offset = intval($offset);
if ($offset < 0) {
throw new Doctrine_Connection_Exception("LIMIT argument offset=$offset is not valid");
throw new DBALException("LIMIT argument offset=$offset is not valid");
}
if ($offset == 0) {
......
......@@ -99,6 +99,31 @@ class MySqlPlatform extends AbstractPlatform
return 'CONCAT(' . join(', ', (array) $args) . ')';
}
public function getDateDiffExpression($date1, $date2)
{
return 'DATEDIFF(' . $date1 . ', ' . $date2 . ')';
}
public function getDateAddDaysExpression($date, $days)
{
return 'DATE_ADD(' . $date . ', INTERVAL ' . (int)$days . ' DAY)';
}
public function getDateSubDaysExpression($date, $days)
{
return 'DATE_SUB(' . $date . ', INTERVAL ' . (int)$days . ' DAY)';
}
public function getDateAddMonthExpression($date, $months)
{
return 'DATE_ADD(' . $date . ', INTERVAL ' . (int)$months . ' MONTH)';
}
public function getDateSubMonthExpression($date, $months)
{
return 'DATE_SUB(' . $date . ', INTERVAL ' . (int)$months . ' MONTH)';
}
public function getListDatabasesSQL()
{
return 'SHOW DATABASES';
......@@ -382,7 +407,7 @@ class MySqlPlatform extends AbstractPlatform
$optionStrings = array();
if (isset($options['comment'])) {
$optionStrings['comment'] = 'COMMENT = ' . $this->quote($options['comment'], 'text');
$optionStrings['comment'] = 'COMMENT = ' . $options['comment'];
}
if (isset($options['charset'])) {
$optionStrings['charset'] = 'DEFAULT CHARACTER SET ' . $options['charset'];
......
......@@ -99,6 +99,31 @@ class OraclePlatform extends AbstractPlatform
{
return 'SYS_GUID()';
}
public function getDateDiffExpression($date1, $date2)
{
return '('.$date1 . '-'.$date2.')';
}
public function getDateAddDaysExpression($date, $days)
{
return '(' . $date . '+' . (int)$days . ')';
}
public function getDateSubDaysExpression($date, $days)
{
return '(' . $date . '-' . (int)$days . ')';
}
public function getDateAddMonthExpression($date, $months)
{
return "ADD_MONTHS(" . $date . ", " . (int)$months . ")";
}
public function getDateSubMonthExpression($date, $months)
{
return "ADD_MONTHS(" . $date . ", -" . (int)$months . ")";
}
/**
* Gets the SQL used to create a sequence that starts with a given value
......@@ -567,7 +592,7 @@ LEFT JOIN all_cons_columns r_cols
* @param integer $offset start reading from given offset
* @return string the modified query
*/
public function modifyLimitQuery($query, $limit, $offset = null)
protected function doModifyLimitQuery($query, $limit, $offset = null)
{
$limit = (int) $limit;
$offset = (int) $offset;
......
......@@ -91,6 +91,31 @@ class PostgreSqlPlatform extends AbstractPlatform
return 'POSITION('.$substr.' IN '.$str.')';
}
}
public function getDateDiffExpression($date1, $date2)
{
return '('.$date1 . '-'.$date2.')';
}
public function getDateAddDaysExpression($date, $days)
{
return "(" . $date . "+ interval '" . (int)$days . " day')";
}
public function getDateSubDaysExpression($date, $days)
{
return "(" . $date . "- interval '" . (int)$days . " day')";
}
public function getDateAddMonthExpression($date, $months)
{
return "(" . $date . "+ interval '" . (int)$months . " month')";
}
public function getDateSubMonthExpression($date, $months)
{
return "(" . $date . "- interval '" . (int)$months . " month')";
}
/**
* parses a literal boolean value and returns
......
......@@ -125,6 +125,31 @@ class SqlitePlatform extends AbstractPlatform
}
}
public function getDateDiffExpression($date1, $date2)
{
return 'ROUND(JULIANDAY('.$date1 . ')-JULIANDAY('.$date2.'))';
}
public function getDateAddDaysExpression($date, $days)
{
return "DATE(" . $date . ",'+". (int)$days . " day')";
}
public function getDateSubDaysExpression($date, $days)
{
return "DATE(" . $date . ",'-". (int)$days . " day')";
}
public function getDateAddMonthExpression($date, $months)
{
return "DATE(" . $date . ",'+". (int)$months . " month')";
}
public function getDateSubMonthExpression($date, $months)
{
return "DATE(" . $date . ",'-". (int)$months . " month')";
}
protected function _getTransactionIsolationLevelSQL($level)
{
switch ($level) {
......
......@@ -159,6 +159,10 @@ class Column extends AbstractAsset
*/
public function setPrecision($precision)
{
if (!is_numeric($precision)) {
$precision = 10; // defaults to 10 when no valid precision is given.
}
$this->_precision = (int)$precision;
return $this;
}
......@@ -169,7 +173,11 @@ class Column extends AbstractAsset
*/
public function setScale($scale)
{
$this->_scale = $scale;
if (!is_numeric($scale)) {
$scale = 0;
}
$this->_scale = (int)$scale;
return $this;
}
......
......@@ -163,6 +163,7 @@ class Comparator
$changes++;
}
}
foreach ( $table1Columns as $columnName => $column ) {
if ( $table2->hasColumn($columnName) ) {
$changedProperties = $this->diffColumn( $column, $table2->getColumn($columnName) );
......@@ -249,7 +250,7 @@ class Comparator
foreach ($tableDifferences->addedColumns AS $addedColumnName => $addedColumn) {
foreach ($tableDifferences->removedColumns AS $removedColumnName => $removedColumn) {
if (count($this->diffColumn($addedColumn, $removedColumn)) == 0) {
$renameCandidates[$addedColumn->getName()][] = array($removedColumn, $addedColumn);
$renameCandidates[$addedColumn->getName()][] = array($removedColumn, $addedColumn, $addedColumnName);
}
}
}
......@@ -257,8 +258,10 @@ class Comparator
foreach ($renameCandidates AS $candidate => $candidateColumns) {
if (count($candidateColumns) == 1) {
list($removedColumn, $addedColumn) = $candidateColumns[0];
$removedColumnName = strtolower($removedColumn->getName());
$addedColumnName = strtolower($addedColumn->getName());
$tableDifferences->renamedColumns[$removedColumn->getName()] = $addedColumn;
$tableDifferences->renamedColumns[$removedColumnName] = $addedColumn;
unset($tableDifferences->addedColumns[$addedColumnName]);
unset($tableDifferences->removedColumns[$removedColumnName]);
}
......@@ -332,7 +335,7 @@ class Comparator
}
if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) {
if ($column1->getPrecision() != $column2->getPrecision()) {
if (($column1->getPrecision()?:10) != ($column2->getPrecision()?:10)) {
$changedProperties[] = 'precision';
}
if ($column1->getScale() != $column2->getScale()) {
......
......@@ -155,7 +155,9 @@ class SqliteSchemaManager extends AbstractSchemaManager
case 'real':
case 'decimal':
case 'numeric':
list($precision, $scale) = array_map('trim', explode(', ', $tableColumn['length']));
if (isset($tableColumn['length'])) {
list($precision, $scale) = array_map('trim', explode(', ', $tableColumn['length']));
}
$length = null;
break;
}
......
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Schema\Visitor;
use Doctrine\DBAL\Platforms\AbstractPlatform,
Doctrine\DBAL\Schema\Table,
Doctrine\DBAL\Schema\Schema,
Doctrine\DBAL\Schema\Column,
Doctrine\DBAL\Schema\ForeignKeyConstraint,
Doctrine\DBAL\Schema\Constraint,
Doctrine\DBAL\Schema\Sequence,
Doctrine\DBAL\Schema\Index;
class Graphviz implements \Doctrine\DBAL\Schema\Visitor\Visitor
{
private $output = '';
public function acceptColumn(Table $table, Column $column)
{
}
public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
{
$this->output .= $this->createNodeRelation(
$fkConstraint->getLocalTableName() . ":col" . current($fkConstraint->getLocalColumns()).":se",
$fkConstraint->getForeignTableName() . ":col" . current($fkConstraint->getForeignColumns()).":se",
array(
'dir' => 'back',
'arrowtail' => 'dot',
'arrowhead' => 'normal',
)
);
}
public function acceptIndex(Table $table, Index $index)
{
}
public function acceptSchema(Schema $schema)
{
$this->output = 'digraph "' . sha1( mt_rand() ) . '" {' . "\n";
$this->output .= 'splines = true;' . "\n";
$this->output .= 'overlap = false;' . "\n";
$this->output .= 'outputorder=edgesfirst;'."\n";
$this->output .= 'mindist = 0.6;' . "\n";
$this->output .= 'sep = .2;' . "\n";
}
public function acceptSequence(Sequence $sequence)
{
}
public function acceptTable(Table $table)
{
$this->output .= $this->createNode(
$table->getName(),
array(
'label' => $this->createTableLabel( $table ),
'shape' => 'plaintext',
)
);
}
private function createTableLabel( Table $table )
{
// Start the table
$label = '<<TABLE CELLSPACING="0" BORDER="1" ALIGN="LEFT">';
// The title
$label .= '<TR><TD BORDER="1" COLSPAN="3" ALIGN="CENTER" BGCOLOR="#fcaf3e"><FONT COLOR="#2e3436" FACE="Helvetica" POINT-SIZE="12">' . $table->getName() . '</FONT></TD></TR>';
// The attributes block
foreach( $table->getColumns() as $column ) {
$columnLabel = $column->getName();
$label .= '<TR>';
$label .= '<TD BORDER="0" ALIGN="LEFT" BGCOLOR="#eeeeec">';
$label .= '<FONT COLOR="#2e3436" FACE="Helvetica" POINT-SIZE="12">' . $columnLabel . '</FONT>';
$label .= '</TD><TD BORDER="0" ALIGN="LEFT" BGCOLOR="#eeeeec"><FONT COLOR="#2e3436" FACE="Helvetica" POINT-SIZE="10">' . strtolower($column->getType()) . '</FONT></TD>';
$label .= '<TD BORDER="0" ALIGN="RIGHT" BGCOLOR="#eeeeec" PORT="col'.$column->getName().'">';
if (in_array($column->getName(), $table->getPrimaryKey()->getColumns())) {
$label .= "\xe2\x9c\xb7";
}
$label .= '</TD></TR>';
}
// End the table
$label .= '</TABLE>>';
return $label;
}
private function createNode( $name, $options )
{
$node = $name . " [";
foreach( $options as $key => $value )
{
$node .= $key . '=' . $value . ' ';
}
$node .= "]\n";
return $node;
}
private function createNodeRelation( $node1, $node2, $options )
{
$relation = $node1 . ' -> ' . $node2 . ' [';
foreach( $options as $key => $value )
{
$relation .= $key . '=' . $value . ' ';
}
$relation .= "]\n";
return $relation;
}
/**
* Write dot language output to a file. This should usually be a *.dot file.
*
* You have to convert the output into a viewable format. For example use "neato" on linux systems
* and execute:
*
* neato -Tpng -o er.png er.dot
*
* @param string $filename
* @return void
*/
public function write($filename)
{
file_put_contents($filename, $this->output . "}");
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
......@@ -30,6 +28,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform,
* A Type object is obtained by calling the static {@link getType()} method.
*
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @since 2.0
*/
abstract class Type
......@@ -227,4 +226,43 @@ abstract class Type
$e = explode('\\', get_class($this));
return str_replace('Type', '', end($e));
}
/**
* Does working with this column require SQL conversion functions?
*
* This is a metadata function that is required for example in the ORM.
* Usage of {@link convertToDatabaseValueSQL} and
* {@link convertToPHPValueSQL} works for any type and mostly
* does nothing. This method can additionally be used for optimization purposes.
*
* @return bool
*/
public function canRequireSQLConversion()
{
return false;
}
/**
* Modifies the SQL expression (identifier, parameter) to convert to a database value.
*
* @param string $sqlExpr
* @param AbstractPlatform $platform
* @return string
*/
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
{
return $sqlExpr;
}
/**
* Modifies the SQL expression (identifier, parameter) to convert to a PHP value.
*
* @param string $sqlExpr
* @param AbstractPlatform $platform
* @return string
*/
public function convertToPHPValueSQL($sqlExpr, $platform)
{
return $sqlExpr;
}
}
\ No newline at end of file
......@@ -244,4 +244,27 @@ class DataAccessTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->assertEquals(5, count($data));
$this->assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data);
}
/**
* @group DDC-1014
*/
public function testDateArithmetics()
{
$p = $this->_conn->getDatabasePlatform();
$sql = 'SELECT ';
$sql .= $p->getDateDiffExpression('test_datetime', "'2010-12-24 12:00:00'") .' AS diff, ';
$sql .= $p->getDateAddDaysExpression('test_datetime', 10) .' AS add_days, ';
$sql .= $p->getDateSubDaysExpression('test_datetime', 10) .' AS sub_days, ';
$sql .= $p->getDateAddMonthExpression('test_datetime', 2) .' AS add_month, ';
$sql .= $p->getDateSubMonthExpression('test_datetime', 2) .' AS sub_month ';
$sql .= 'FROM fetch_table';
$row = $this->_conn->fetchAssoc($sql);
$this->assertEquals(-357, (int)$row['diff'], "Date difference should be -356 days.");
$this->assertEquals('2010-01-11', date('Y-m-d', strtotime($row['add_days'])), "Adding date should end up on 2010-01-11");
$this->assertEquals('2009-12-22', date('Y-m-d', strtotime($row['sub_days'])), "Subtracting date should end up on 2009-12-22");
$this->assertEquals('2010-03-01', date('Y-m-d', strtotime($row['add_month'])), "Adding month should end up on 2010-03-01");
$this->assertEquals('2009-11-01', date('Y-m-d', strtotime($row['sub_month'])), "Adding month should end up on 2009-11-01");
}
}
\ No newline at end of file
......@@ -625,6 +625,48 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$this->assertArrayHasKey('id', $tableDiff->changedColumns);
}
/**
* @group DBAL-105
*/
public function testDiff()
{
$table = new \Doctrine\DBAL\Schema\Table('twitter_users');
$table->addColumn('id', 'integer', array('autoincrement' => true));
$table->addColumn('twitterId', 'integer', array('nullable' => false));
$table->addColumn('displayName', 'string', array('nullable' => false));
$table->setPrimaryKey(array('id'));
$newtable = new \Doctrine\DBAL\Schema\Table('twitter_users');
$newtable->addColumn('id', 'integer', array('autoincrement' => true));
$newtable->addColumn('twitter_id', 'integer', array('nullable' => false));
$newtable->addColumn('display_name', 'string', array('nullable' => false));
$newtable->addColumn('logged_in_at', 'datetime', array('nullable' => true));
$newtable->setPrimaryKey(array('id'));
$c = new Comparator();
$tableDiff = $c->diffTable($table, $newtable);
$this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
$this->assertEquals(array('twitterid', 'displayname'), array_keys($tableDiff->renamedColumns));
$this->assertEquals(array('logged_in_at'), array_keys($tableDiff->addedColumns));
$this->assertEquals(0, count($tableDiff->removedColumns));
}
/**
* @group DBAL-106
*/
public function testDiffDecimalWithNullPrecision()
{
$column = new Column('foo', Type::getType('decimal'));
$column->setPrecision(null);
$column2 = new Column('foo', Type::getType('decimal'));
$c = new Comparator();
$this->assertEquals(array(), $c->diffColumn($column, $column2));
}
/**
* @param SchemaDiff $diff
* @param int $newTableCount
......
......@@ -39,4 +39,11 @@ class StringTest extends \Doctrine\Tests\DbalTestCase
{
$this->assertNull($this->_type->convertToPHPValue(null, $this->_platform));
}
public function testSQLConversion()
{
$this->assertFalse($this->_type->canRequireSQLConversion(), "String type can never require SQL conversion to work.");
$this->assertEquals('t.foo', $this->_type->convertToDatabaseValueSQL('t.foo', $this->_platform));
$this->assertEquals('t.foo', $this->_type->convertToPHPValueSQL('t.foo', $this->_platform));
}
}
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