[DC-340] Pager does not work with MS SQL Server Created: 08/Dec/09  Updated: 03/Mar/10  Resolved: 03/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Pager
Affects Version/s: 1.2.0
Fix Version/s: None

Type: Bug Priority: Blocker
Reporter: lr Assignee: Guilherme Blanco
Resolution: Duplicate Votes: 0
Labels: None
Environment:

Windows 2003 Server. IIS 6.0. MS SQL Server 2005. Symfony 1.4



 Description   

Hi,

I can't use a pager. For example :
$q = Doctrine_Query::create()>select( "*" )>from( "utilisateur" );

$pager = new customDoctrinePager( $q, 1, 10 );
$pager->init();

$results = $pager->getResults();

gives me :
SQLSTATE[HY000]: General error: 10007 Invalid column name 'id'. [10007] (severity 5) [SELECT TOP 10 [inner_tbl].[id] AS [u__id] FROM (SELECT TOP 10 [u].[id] AS [u__id], [u].[utisateurnom] AS [u__utisateurnom] FROM [utilisateur] [u]) AS [inner_tbl]]. Failing Query: "SELECT TOP 10 [inner_tbl].[id] AS [u__id] FROM (SELECT TOP 10 [u].[id] AS [u__id], [u].[utisateurnom] AS [u__utisateurnom] FROM [utilisateur] [u]) AS [inner_tbl]"

The query :
SELECT
TOP 10 [inner_tbl].[id] AS [u__id]
FROM
(
SELECT
TOP 10 [u].[id] AS [u__id], [u].[utisateurnom] AS [u__utisateurnom]
FROM
[utilisateur] [u]
) AS [inner_tbl]

is wrong.

This one would be correct :
SELECT
TOP 10 [inner_tbl].[u__id] AS [u__id]
FROM
(
SELECT
TOP 10 [u].[id] AS [u__id], [u].[utisateurnom] AS [u__utisateurnom]
FROM
[utilisateur] [u]
) AS [inner_tbl]

This code works :
$q = Doctrine_Query::create()
->select( '*' )
->from( 'utilisateur u' );
$this->resultSet = $q->execute();

This one gives the save error :
$q = Doctrine_Query::create()
->select( '*' )
->from( 'utilisateur u' );

$q->limit(10);
$q->offset(1);
$this->resultSet = $q->execute();

This is very blocker for me.

Nb. I am not sure of the Doctrine's version used by symfony 1.4



 Comments   
Comment by lr [ 10/Dec/09 ]

Same problem with
$this->produit = Doctrine::getTable( "TProduit" )>find( $request>getParameter("produitId") );

The inner query gives

t__produit_id

but the main query tries to select

[inner_tbl].[produit_id]

Comment by Olivier Sieffert [ 10/Dec/09 ]

Same problem when use the pager, since Doctrine 1.2.0rc2. My config: Linux Apache/PHP5.3, SQL Server 2000

Comment by Michael Card [ 18/Dec/09 ]

Duplicate of DC-289. Should be closed as duplicate.

Comment by Guilherme Blanco [ 03/Mar/10 ]

DC-289 refers to same issue and it's already committed. Everything should be working now.





[DC-300] synchronizeWithArray deletes Entries in RefTable when updating related Entries Created: 30/Nov/09  Updated: 15/Mar/10  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Record, Relations
Affects Version/s: 1.2.0-RC1
Fix Version/s: 1.2.2

Type: Bug Priority: Blocker
Reporter: Marcus Häußler Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: File DC300TestCase.php    

 Description   

You have Users and Groups with a ManyToMany relation (refClass = UserGroup).
Then you do a synchronizeWithArray() on a user:

 
$user->synchronizeWithArray(array(
    'Groups' => array(
        array('name' => 'updated Group')
    )
));

When you update a record with synchronizeWithArray() and you update ManyToMany related entries, the RefTable entries gets deleted.

I think the problem is located near:
Doctrine_Record line 2024:

 
        // Eliminate relationships missing in the $array
        foreach ($this->_references as $name => $relation) {
	        $rel = $this->getTable()->getRelation($name);
	
// PROBLEM: RefClass "UserGroup" will never be set in the sync-Array (just "Groups"), so all entries in UserGroup-Table will be deleted
// only new Groups that are synced will be created with a link in the refTable
		if ( ! isset($array[$name]) && ( ! $rel->isOneToOne() || ! isset($array[$rel->getLocalFieldName()]))) {
                    unset($this->$name);
                }
        }

TestCase follows.



 Comments   
Comment by Marcus Häußler [ 30/Nov/09 ]

TestCase

Comment by Jonathan H. Wage [ 30/Nov/09 ]

This one is proving to be very tricky to fix. Any suggestions or ideas for solutions would be appreciated.

Comment by Marcus Häußler [ 30/Nov/09 ]

Is there any possibilty to check wether a relation is used as "refClass"?
In setUp() you say hasMany(array([..], 'refClass' => 'UserGroup')), but i could not find this information in the relation-object.

Then you could do something like this

if ( ! isset($array[$name]) && ( (!$rel->isRefClass() && ! $rel->isOneToOne()) || ! isset($array[$rel->getLocalFieldName()]))) {
    unset($this->$name);
}

The unlinking works anyway.

Comment by Jonathan H. Wage [ 07/Dec/09 ]

This fixes your test case but I want to test it before we include it in a release(1.2.2)

Index: lib/Doctrine/Relation.php
===================================================================
--- lib/Doctrine/Relation.php	(revision 6882)
+++ lib/Doctrine/Relation.php	(working copy)
@@ -74,6 +74,8 @@
                                   'orderBy' => null
                                   );
 
+    protected $_isRefClass = null;
+
     /**
      * constructor
      *
@@ -416,6 +418,24 @@
         }
     }
 
+    public function isRefClass()
+    {
+        if ($this->_isRefClass === null) {
+            $this->_isRefClass = false;
+            $table = $this->getTable();
+            foreach ($table->getRelations() as $name => $relation) {
+                foreach ($relation['table']->getRelations() as $relation) {
+                    if (isset($relation['refTable']) && $relation['refTable'] === $table) {
+                        $this->_isRefClass = true;
+                        break(2);
+                    }
+                }
+            }
+        }
+
+        return $this->_isRefClass;
+    }
+
     /**
      * __toString
      *
Index: lib/Doctrine/Record.php
===================================================================
--- lib/Doctrine/Record.php	(revision 6882)
+++ lib/Doctrine/Record.php	(working copy)
@@ -2024,8 +2024,8 @@
         // Eliminate relationships missing in the $array
         foreach ($this->_references as $name => $relation) {
 	        $rel = $this->getTable()->getRelation($name);
-	
-			if ( ! isset($array[$name]) && ( ! $rel->isOneToOne() || ! isset($array[$rel->getLocalFieldName()]))) {
+
+            if ( ! $rel->isRefClass() && ! isset($array[$name]) && ( ! $rel->isOneToOne() || ! isset($array[$rel->getLocalFieldName()]))) {
                 unset($this->$name);
             }
         }
Index: tests/Ticket/DC300TestCase.php
===================================================================
--- tests/Ticket/DC300TestCase.php	(revision 0)
+++ tests/Ticket/DC300TestCase.php	(revision 0)
@@ -0,0 +1,127 @@
+<?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
+ * 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.phpdoctrine.org>.
+ */
+
+/**
+ * Doctrine_Ticket_DC300_TestCase
+ *
+ * @package     Doctrine
+ * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
+ * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @category    Object Relational Mapping
+ * @link        www.phpdoctrine.org
+ * @since       1.0
+ * @version     $Revision$
+ */
+class Doctrine_Ticket_DC300_TestCase extends Doctrine_UnitTestCase
+{
+    public function prepareData()
+    {
+        $g1 = new Ticket_DC300_Group();
+        $g1['name'] = 'group1';
+        $g1->save();
+
+        $g2 = new Ticket_DC300_Group();
+        $g2['name'] = 'group2';
+        $g2->save();
+
+        $g3 = new Ticket_DC300_Group();
+        $g3['name'] = 'group3';
+        $g3->save();
+
+        $u1 = new Ticket_DC300_User();
+        $u1['name'] = 'user1';
+        $u1['Groups']->add($g1);
+        $u1['Groups']->add($g2);
+        $u1->save();
+    }
+
+    public function prepareTables()
+    {
+        $this->tables[] = 'Ticket_DC300_Group';
+        $this->tables[] = 'Ticket_DC300_User';
+        $this->tables[] = 'Ticket_DC300_UserGroup';
+        parent::prepareTables();
+    }
+
+    public function testRefTableEntriesOnManyToManyRelationsWithSynchronizeWithArray()
+    {
+		$u1 = Doctrine::getTable('Ticket_DC300_User')->find(1);
+
+		// update the groups user (id 1) is linked to
+		$u1->synchronizeWithArray(array(
+			'Groups' => array(
+				array('name' => 'group1 update'),
+				array('name' => 'group2 update')
+			)
+		));
+		$u1->save();
+
+		// update the user-objects with real data from database
+		$u1->loadReference('Groups');
+
+		// check wether the two database-entries in RefTable exists
+		$this->assertEqual(count($u1->Groups), 2);
+    }
+   
+}
+
+class Ticket_DC300_Group extends Doctrine_Record
+{
+	public function setTableDefinition()
+	{
+		$this->hasColumn('name', 'string', 255);
+	}
+	
+	public function setUp()
+	{
+		$this->hasMany('Ticket_DC300_User as Users', array(
+			'local' => 'group_id',
+			'foreign' => 'user_id',
+			'refClass' => 'Ticket_DC300_UserGroup'
+		));
+	}
+}
+
+class Ticket_DC300_User extends Doctrine_Record
+{
+	public function setTableDefinition()
+	{
+		$this->hasColumn('name', 'string', 255);
+	}
+
+	public function setUp()
+	{
+		$this->hasMany('Ticket_DC300_Group as Groups', array(
+			'local' => 'user_id',
+			'foreign' => 'group_id',
+			'refClass' => 'Ticket_DC300_UserGroup'
+		));
+	}
+}
+
+class Ticket_DC300_UserGroup extends Doctrine_Record
+{
+	public function setTableDefinition()
+	{
+		$this->hasColumn('user_id', 'integer');
+		$this->hasColumn('group_id', 'integer');
+	}
+}
\ No newline at end of file
Comment by Marcus Häußler [ 09/Dec/09 ]

I tested your patch in our project and it seems to work very well.

Thank you and your team for the good work !





[DC-277] Doctrine_Core::loadModels() is getting class name from file name and not the actual class name Created: 23/Nov/09  Updated: 24/Nov/09  Resolved: 24/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.0-BETA3
Fix Version/s: None

Type: Bug Priority: Blocker
Reporter: Juozas Kaziukenas Assignee: Jonathan H. Wage
Resolution: Invalid Votes: 0
Labels: None


 Description   

If models has any prefix Doctrine_Core::loadModels() fails as fails all export scripts, because for models:

Model_Test
Model_Test2

it returns:

array(
'Test' => 'Test',
'Test2' => 'Test2'
)

This is incorrect and Doctrine_Core::filterInvalidModels() filters out these classes, hence none of the models become available.

Expected behaviour: classPrefix should be possible to pass to configuration of task (now I need to manually copy/paste/edit all tasks to add required class prefix).



 Comments   
Comment by Jonathan H. Wage [ 23/Nov/09 ]

I made a fix in Doctrine 1.2 that should help. Be sure you set the model loading to be pear style.

$manager->setAttribute(Doctrine_Core::ATTR_MODEL_LOADING, Doctrine_Core::MODEL_LOADING_PEAR);
Comment by Juozas Kaziukenas [ 24/Nov/09 ]

It does fix some things, I will explain the problem in more detail:

I have models like this (zf-style)

$options = array(
'pearStyle' => true,
'generateTableClasses' => true,
'classPrefix' => 'Model_',
'baseClassPrefix' => 'Base_',
'baseClassesDirectory' => null,
'classPrefixFiles' => false,
'generateAccessors' => false,
);

As you can see, models doesn't have a folder Model, they are just in folder models, so my result is:

./models
....Product.php --> Model_Product
....Base
........Product.php --> Model_Base_Product

Hence the prefix cannot be determined from folder name as it can be anything I want.

Possible fix: take into account prefix (define as a property?) or use reflection.

Comment by Jonathan H. Wage [ 24/Nov/09 ]

You need to have 'classPrefixFiles' => true. With pearStyle it is required that the name of your class represent the path to the class on disk. So if you change classPrefixFiles to true everything will be fine and work the way it is supposed to. The prefix option for loadModels is not recommended.





[DC-210] PEAR style models generation produces unusable table classes Created: 11/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Blocker
Reporter: Juozas Kaziukenas Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

When generating models like:

'pearStyle' => true,
'generateTableClasses' => true,
'classPrefix' => 'Model_',
'baseClassPrefix' => 'Base_',
'baseClassesDirectory' => 'Base',
'classPrefixFiles' => true

or

'pearStyle' => true,
'generateTableClasses' => true,
'classPrefix' => 'Model_',
'baseClassPrefix' => 'Base_',
'baseClassesDirectory' => 'Base',
'classPrefixFiles' => false

Produced files are like this:

Model_ModelName extends Base_ModelName
Base_ModelName extends Doctrine_Record
ModelNameTable extends Doctrine_Table

Problem is ModelNameTable class is not prefixed with "Model_" and thus cannot be autoloaded.






[DC-183] Undefined constant Doctrine_Core::ATTR_DEFAULT_TEXTFLD_LENGTH Created: 04/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Native SQL
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Blocker
Reporter: Juozas Kaziukenas Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

All



 Description   

File http://trac.doctrine-project.org/browser/branches/1.2/lib/Doctrine/DataDict/Sqlite.php

Contains undefined constant Doctrine_Core::ATTR_DEFAULT_TEXTFLD_LENGTH which breaks generation of sql for sqlite

Proposed fix: use $this->conn->options['default_text_field_length'] ?



 Comments   
Comment by Juozas Kaziukenas [ 13/Nov/09 ]

I've tested it again and now it seems to be broken in that same line.

Now in 76 line of Doctrine_DataDict_Sqlite I need to use:

return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->varchar_max_length.')')

Which I found in Mysql datadict, even though Mssql uses:

return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->options['default_text_field_length'].')')

Which won't work because there is no options in conn.

Using rev6721

Comment by Juozas Kaziukenas [ 13/Nov/09 ]

It is caused by the fact that $options in connection are (now?) protected, hence cannot be accessed like that. There is way to access them by:

return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->getOption('default_text_field_length').')')

But key doesn't exist and return value is null.





[DC-66] Saving "new Doctrine_Expression('NOW()')" to database doesn't work since r6403 Created: 25/Sep/09  Updated: 06/Oct/09  Resolved: 06/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: Record
Affects Version/s: 1.2.0-ALPHA2
Fix Version/s: 1.2.0-ALPHA2

Type: Bug Priority: Blocker
Reporter: Marcin Gil Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 4
Labels: None
Environment:

MySQL 5.0.51, PHP 5.3


Attachments: Text File timestamp-validation.patch    

 Description   

Doctrine_Record:1469

} else if ($type == 'timestamp' || $type == 'date') {
return strtotime($old) !== strtotime($new);

These new lines cause inability to save NOW() to "date" field.

Change was commited in r6403 branch 1.2

MySQL error is:

SQLSTATE[HY000]: General error: 1364 Field 'date' doesn't have a default value



 Comments   
Comment by Lex Brugman [ 27/Sep/09 ]

Possible fix attached.

Comment by Marcin Gil [ 28/Sep/09 ]

The patch is effective, please apply to SVN.

Thanks!

Comment by Johannes Weber [ 28/Sep/09 ]

I don't want to rewrite all my "NOW()" values! Please fix this ASAP!
thx!





[DC-69] Linking between one to one relations with synchronizeWithArray fails Created: 28/Sep/09  Updated: 02/Nov/09  Resolved: 02/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Relations
Affects Version/s: 1.0.12, 1.1.4, 1.2.0-ALPHA1
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Blocker
Reporter: Marcus Häußler Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

tested on
MySQL
Doctrine Version 1.0.11 Revision: 6380
Doctrine Version 1.1.3 Revision: 6380
Doctrine Version 1.1.4 Revision: 6409
Doctrine Version 1.2



 Description   

Linking between one to one relations with synchronizeWithArray() ends up in an error message.

Example:
Group has one User
User has one Group

When I have a group-object and do the following:

$group->synchronizeWithArray(array(
	'User' => array(1)
));
$group->save();

I get the message: "Fatal error: Call to a member function identifier() on a non-object in [..]lib/Doctrine/Record.php on line 2327"

Apparantly $this->_references[$alias] should be an collection, but in an one to one relation it is a record (which makes sense in my opinion).



 Comments   
Comment by Marcus Häußler [ 01/Oct/09 ]

I just realized that the whole linking process in one to one relations is not working.

A simple

$group->link('User', 1);

ends up in <b>Fatal error</b>: Uncaught exception 'Doctrine_Exception' with message 'Add is not supported for User' in [..]/Doctrine/Access.php:201

Because in Doctrine_Record the add-method is completely missing
I hope it's just more or less a copy/past of Doctrine_Collection->add()

Comment by Marcus Häußler [ 09/Oct/09 ]

I have build a fix that works for me, but I did not tested it fully.

Index: library/Doctrine/Doctrine/Record.php
===================================================================
--- library/Doctrine/Doctrine/Record.php        (Revision 6462)
+++ library/Doctrine/Doctrine/Record.php        (Arbeitskopie)
@@ -2323,13 +2323,23 @@
         }

         if (isset($this->_references[$alias])) {
-            foreach ($this->_references[$alias] as $k => $record) {
-                if (in_array(current($record->identifier()), $ids) || empty($ids)) {
-                    $this->_references[$alias]->remove($k);
-                }
-            }

-            $this->_references[$alias]->takeSnapshot();
+                       /*
+                        * Fix for One To One Relations
+                        */
+               if ($this->_references[$alias] instanceof Doctrine_Record) {
+                       if (in_array($this->_references[$alias]->identifier(), $ids) || empty($ids)) {
+                               unset($this->_references[$alias]);
+                       }
+               } else {
+                       foreach ($this->_references[$alias] as $k => $record) {
+                               if (in_array(current($record->identifier()), $ids) || empty($ids)) {
+                                       $this->_references[$alias]->remove($k);
+                               }
+                       }
+                   $this->_references[$alias]->takeSnapshot();
+               }
+
         }

         if ( ! $this->exists() || $now === false) {
@@ -2406,7 +2416,14 @@
                 ->execute();

             foreach ($records as $record) {
-                $this->$alias->add($record);
+               /*
+                * Fix for One To One Relations
+                */
+               if ($this->$alias instanceof Doctrine_Record) {
+                       $this->$alias = $record;
+               } else {
+                       $this->$alias->add($record);
+               }
             }




[DC-40] Problems with alias in where section Created: 18/Sep/09  Updated: 24/Sep/09  Resolved: 24/Sep/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.2.0-ALPHA1
Fix Version/s: 1.2.0-ALPHA2

Type: Bug Priority: Blocker
Reporter: Johannes Weber Assignee: Roman S. Borschel
Resolution: Invalid Votes: 0
Labels: None
Environment:

MAMP



 Description   

I'm using a mysql function to calculate the distance between 2 points. When I'm using this funciton in a doctrine query it works. But when I'm using the functions result in a where clause it dont work:

The Query:
$basicQuery = $query->select('id, getGeoDistanceKM(lng, lat, '.$points['lng'].', '.$points['lat'].') AS distance, getGeoDistanceKM(lng, lat, '.$points['lng'].', '.$points['lat'].') AS distance, IF(count(r.id) > 0, AVG(r.rating), 0) as ratingAvg')
->from('ProomsOffer o')
->leftJoin('o.PublicTransports pt')
->leftJoin('o.Unavailabilities ua')
->leftJoin('o.Ratings r')
->leftJoin('o.Bookings b')
->where('distance != 0')
->groupBy('o.id')
->orderBy('distance, ratingAvg');

The Error message:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'm__1' in 'where clause'
#0 /Applications/MAMP/htdocs/prooms/cms/library/Doctrine/Doctrine/Connection.php(1015): Doctrine_Connection->rethrowException(Object(PDOException), Object(Doctrine_Connection_Mysql))
#1 /Applications/MAMP/htdocs/prooms/cms/library/Doctrine/Doctrine/Connection.php(790): Doctrine_Connection->execute('SELECT COUNT...', Array)
#2 /Applications/MAMP/htdocs/prooms/cms/library/Doctrine/Doctrine/Query.php(2037): Doctrine_Connection->fetchAll('SELECT COUNT...', Array)
#3 /Applications/MAMP/htdocs/prooms/cms/application/modules/prooms/controllers/SearchController.php(163): Doctrine_Query->count()
#4 /Applications/MAMP/htdocs/prooms/cms/library/Zend/Controller/Action.php(513): Prooms_SearchController->searchAction()
#5 /Applications/MAMP/htdocs/prooms/cms/library/Zend/Controller/Dispatcher/Standard.php(289): Zend_Controller_Action->dispatch('searchAction')
#6 /Applications/MAMP/htdocs/prooms/cms/library/Zend/Controller/Front.php(946): Zend_Controller_Dispatcher_Standard->dispatch(Object(CMS_Controller_Request), Object(Zend_Controller_Response_Http))
#7 /Applications/MAMP/htdocs/prooms/cms/library/CMS/Application.php(372): Zend_Controller_Front->dispatch()
#8 /Applications/MAMP/htdocs/prooms/cms/library/CMS/Application.php(241): CMS_Application->_dispatch(Object(Zend_Controller_Front))
#9 /Applications/MAMP/htdocs/prooms/cms/public/index.php(50): CMS_Application->run()
#10

{main}

The getSqlQuery:
SELECT `m`.`id` AS `m_id`, getGeoDistanceKM(`m`.`lng`, `m`.`lat`, 48.2092062, 16.3727778) AS `m0`, getGeoDistanceKM(`m`.`lng`, `m`.`lat`, 48.2092062, 16.3727778) AS `m1`, IF(COUNT(`m4`.`id`) > 0, AVG(`m4`.`rating`), 0) AS `m41` FROM `module_prooms_offers` `m` LEFT JOIN `module_prooms_offers_public_transport` `m2` ON `m`.`id` = `m2`.`id_offer` LEFT JOIN `module_prooms_offers_unavailability` `m3` ON `m`.`id` = `m3`.`id_offer` LEFT JOIN `module_prooms_offers_ratings` `m4` ON `m`.`id` = `m4`.`id_offer` LEFT JOIN `module_prooms_bookings` `m5` ON `m`.`id` = `m5`.`id_offer` WHERE `m1` != 0 GROUP BY `m`.`id` ORDER BY `m1`, `m4_1`



 Comments   
Comment by Guilherme Blanco [ 24/Sep/09 ]

You must disable PORTABILITY_EXPR in order to get it working correcrly.





[DC-561] Doctrine autoloader tries to load class again and fails with fatal error - with fix Created: 10/Mar/10  Updated: 15/Mar/10  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Blocker
Reporter: Miha Vrhovnik Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

Doctrine_Core::autoload around line 1107
if (strpos($className, 'sfYaml') === 0 || class_exists($className, false)) {

should be changed to

if (strpos($className, 'sfYaml') === 0) {

otherwise you get:
Warning: require(/srv/www/pacs.lan/site/lib/Doctrine/Parser/sfYaml/Doctrine_Query_From.php) [function.require]: failed to open stream: No such file or directory in /srv/www/pacs.lan/site/lib/Doctrine/Core.php on line 1108

Fatal error: require() [function.require]: Failed opening required '/srv/www/pacs.lan/site/lib/Doctrine/Parser/sfYaml/Doctrine_Query_From.php' (include_path='/srv/www/pacs.lan/site/lib/:/srv/www/pacs.lan/site/lib/Dwoo/:.:/usr/local/lib/php') in /srv/www/pacs.lan/site/lib/Doctrine/Core.php on line 1108



 Comments   
Comment by Jonathan H. Wage [ 15/Mar/10 ]

It appears this is already fixed in the latest SVN of 1.2.





[DC-508] All but the first migrations fail with PostgreSQL [patch included] Created: 17/Feb/10  Updated: 15/Mar/10  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Migrations
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Blocker
Reporter: Elnur Abdurrakhimov Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: File patch-doctrine-migration-pgsql-2.diff     File patch-migration-pgsql.diff     File patch-migrations.diff    

 Description   

The problem is in this method:

protected function _createMigrationTable()
{
    if ($this->_migrationTableCreated) {
        return true;
    }

    $this->_migrationTableCreated = true;

    try {
        $this->_connection->export->createTable($this->_migrationTableName, array('version' => array('type' => 'integer', 'size' => 11)));

        return true;
    } catch(Exception $e) {
        return false;
    }
}

When migration_version table doesn't exist, everything works like it should. But subsequent migrations fail, because after failing at creating migration_version table every subsequent queries in that transaction fail.

It works flawlessly with MySQL, but fails with PostgreSQL.



 Comments   
Comment by Elnur Abdurrakhimov [ 20/Feb/10 ]

My previous patch broke MySQL migrations. This new patch resolves that problem.

My solution is not neat, but at least migrations work and I can continue developing my project.

Comment by Jonathan H. Wage [ 01/Mar/10 ]

This isn't really a good patch. I don't wanna have driver specific conditional statements like that.

What about if we started and committed our own transaction for the create table so that everything else is in another transaction and would not conflict.

Comment by Elnur Abdurrakhimov [ 15/Mar/10 ]

This time solution is neater.

Comment by Elnur Abdurrakhimov [ 15/Mar/10 ]

Provided a patch with a neater solution.

Comment by Jonathan H. Wage [ 15/Mar/10 ]

Thanks for following up on this and fixing the root cause of the problem.





[DC-242] Linking (re-linking) o/m2m relations with array of ids in Doctrine_Record fromArray stopped working Created: 17/Nov/09  Updated: 17/Nov/09  Resolved: 17/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Record
Affects Version/s: 1.2.0-BETA3
Fix Version/s: 1.2.0-RC1

Type: Bug Priority: Blocker
Reporter: Maciej Hołyszko Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 1
Labels: None
Environment:

1.2 svn



 Description   
class User extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->hasColumn('username', 'string', 64, array('notnull' => true));
		$this->hasColumn('password', 'string', 128, array('notnull' => true));
	}
	
	public function setUp()
	{
		$this->hasMany('Role as Roles', array('local' => 'id_user', 'foreign' => 'id_role', 'refClass' => 'UserRole'));
		$this->actAs('SoftDelete');
	}
}

class Role extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->hasColumn('name', 'string', 64);
	}
	
	public function setUp()
	{
		$this->hasMany('User as Users', array('local' => 'id_role', 'foreign' => 'id_user', 'refClass' => 'UserRole'));
	}
}

class UserRole extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->hasColumn('id_user', 'integer', null, array('primary' => true));
		$this->hasColumn('id_role', 'integer', null, array('primary' => true));
	}
	
	public function setUp()
	{
		$this->hasOne('User', array('local' => 'id_user', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
		$this->hasOne('Role', array('local' => 'id_role', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
	}
}


$role = new Role();
$role->name = 'publisher';
$role->save();

$role = new Role();
$role->name = 'reviewer';
$role->save();

$role = new Role();
$role->name = 'mod';
$role->save();

$user = new User();
$user->fromArray(array(
	'username' => 'test',
	'password' => 'test',
	'Roles' => array(1, 2, 3),
));
$user->save();

//--------------------- here goes the failure
$user->fromArray(array(
	'Roles' => array(1, 3),
));
$user->save();

After a User is saved once with some roles, it cannot be saved here with another combination of roles, consisting of some roles which was saved to the User before.
In short, ->unlink() in fromArray method does not schedule a deletion of old relations before adding new ones on save, like it was in previous versions of Doctrine.
Hence the primary key constraint is violated and the exception is thrown:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 1
#0 D:\projekty\cms-trunk\cms\library\Doctrine\Doctrine\Connection\Statement.php(269): Doctrine_Connection->rethrowException(Object(PDOException), Object(Doctrine_Connection_Statement))
#1 (...)\library\Doctrine\Doctrine\Connection.php(1032): Doctrine_Connection_Statement->execute(Array)
#2 (...)\library\Doctrine\Doctrine\Connection.php(677): Doctrine_Connection->exec('INSERT INTO `us...', Array)
#3 (...)\library\Doctrine\Doctrine\Connection\UnitOfWork.php(631): Doctrine_Connection->insert(Object(Doctrine_Table), Array)
#4 (...)\library\Doctrine\Doctrine\Connection\UnitOfWork.php(562): Doctrine_Connection_UnitOfWork->processSingleInsert(Object(UserRole))
#5 (...)\library\Doctrine\Doctrine\Connection\UnitOfWork.php(81): Doctrine_Connection_UnitOfWork->insert(Object(UserRole))
#6 (...)\library\Doctrine\Doctrine\Connection\UnitOfWork.php(452): Doctrine_Connection_UnitOfWork->saveGraph(Object(UserRole))
#7 (...)\library\Doctrine\Doctrine\Connection\UnitOfWork.php(137): Doctrine_Connection_UnitOfWork->saveAssociations(Object(User))
#8 (...)\library\Doctrine\Doctrine\Record.php(1690): Doctrine_Connection_UnitOfWork->saveGraph(Object(User))
#9 (...)\test3.php(124): Doctrine_Record->save()
#10

{main}

 Comments   
Comment by Maciej Hołyszko [ 17/Nov/09 ]

Now I see I duplicated the following ticket: DC-228
Please fix this issue.

Comment by Maciej Hołyszko [ 17/Nov/09 ]

Aaand DC-189 is also related.





[DC-241] Count query with join o2m + limit + where throws an exception Created: 17/Nov/09  Updated: 17/Nov/09  Resolved: 17/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Record, Relations
Affects Version/s: 1.2.0-BETA3
Fix Version/s: 1.2.0-RC1

Type: Bug Priority: Blocker
Reporter: Maciej Hołyszko Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 1
Labels: None
Environment:

1.2 svn



 Description   
class Poll extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->setTableName('module_polls');
		
		$this->hasColumn('id_category', 'integer', null, array('notnull' => true));
		$this->hasColumn('question', 'string', 256);
	}
	
	public function setUp()
	{
		$this->hasMany('PollAnswer as Answers', array('local' => 'id', 'foreign' => 'id_poll', 'orderBy' => 'position'));
	}
}

class PollAnswer extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->setTableName('module_polls_answers');
		
		$this->hasColumn('id_poll', 'integer', null, array('notnull' => true));
		$this->hasColumn('answer', 'string', 256);
		$this->hasColumn('votes', 'integer', null, array('notnull' => true, 'default' => 0));
		$this->hasColumn('position', 'integer');
	}
	
	public function setUp()
	{
		$this->hasOne('Poll', array('local' => 'id_poll', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
	}
}

$query = Doctrine_Query::create()
	->from('Poll p')
	->leftJoin('p.Answers pa')
	->where('id_category = ?', 1)
	->limit(10);

print_r($query->count());

This fails with the following exception being thrown:

SQLSTATE[42000]: Syntax error or access violation: 1064 Something is wrong in your syntax obok '? LIMIT 10' w linii 1. Failing Query: "SELECT DISTINCT `m3`.`id` FROM `module_polls` `m3` LEFT JOIN `module_polls_answers` `m4` ON `m3`.`id` = `m4`.`id_poll` WHERE `m3`.`id_category` = ? LIMIT 10"
#0 (...)\library\Doctrine\Doctrine\Connection.php(1015): Doctrine_Connection->rethrowException(Object(PDOException), Object(Doctrine_Connection_Mysql), 'SELECT DISTINCT...')
#1 (...)\library\Doctrine\Doctrine\Query.php(1246): Doctrine_Connection->execute('SELECT DISTINCT...', Array)
#2 (...)\library\Doctrine\Doctrine\Query.php(1106): Doctrine_Query->buildSqlQuery()
#3 (...)\library\Doctrine\Doctrine\Query\Abstract.php(1126): Doctrine_Query->getSqlQuery(Array)
#4 (...)\library\Doctrine\Doctrine\Query\Abstract.php(1088): Doctrine_Query_Abstract->_getDqlCallbackComponents(Array)
#5 (...)\library\Doctrine\Doctrine\Query.php(1126): Doctrine_Query_Abstract->_preQuery()
#6 (...)\library\Doctrine\Doctrine\Query.php(1106): Doctrine_Query->buildSqlQuery()
#7 (...)\library\Doctrine\Doctrine\Query.php(1995): Doctrine_Query->getSqlQuery()
#8 (...)\library\Doctrine\Doctrine\Query.php(2091): Doctrine_Query->getCountSqlQuery()
#9 (...)\test2.php(123): Doctrine_Query->count()
#10

{main}

You can see the generated query which is wrong, moreover it is passed with an empty params array().
Without either where condition or limit removed, it works. With a combo of both of them it fails.

E.g. without where condition the following query is generated:
SELECT COUNT AS `num_results` FROM (SELECT `m`.`id` FROM `module_polls` `m` LEFT JOIN `module_polls_answers` `m2` ON `m`.`id` = `m2`.`id_poll` GROUP BY `m`.`id`) `dctrn_count_query`



 Comments   
Comment by Maciej Hołyszko [ 17/Nov/09 ]

This is related to recently closed, but not fixed due to unability to reproduce, DC-138 - seems like the same problem. In that ticket it was not clearly stated that ->count() method is used on the query. It fails when a 'where' condition is added to the query, no matter if it's simple =? condition or LIKE one.

Comment by Jonathan H. Wage [ 17/Nov/09 ]

I am not sure that these are the same issues. Can you test this patch though?

Index: lib/Doctrine/Query.php
===================================================================
--- lib/Doctrine/Query.php	(revision 6739)
+++ lib/Doctrine/Query.php	(working copy)
@@ -1334,15 +1334,6 @@
             array_pop($this->_sqlParts['where']);
         }
 
-        if ($needsSubQuery) {
-            // We need to double shift if > 2
-            if (count($this->_sqlParts['where']) > 2) {
-                array_shift($this->_sqlParts['where']);
-            }
-
-            array_shift($this->_sqlParts['where']);
-        }
-
         $this->_sql = $q;
 
         $this->clear();

I think this should fix the issue. I am not sure what that block of code is supposed to be doing, but I think it is there incorrectly.

Comment by Maciej Hołyszko [ 17/Nov/09 ]

Unfortunately this patch does not fix the problem. The result is the same exception being thrown.
I think that part of code is there for some purpose, are you sure that removing will not break anything else? It is steered by $needsSubQuery variable which is set to true or false in few conditions above it.

Comment by Jonathan H. Wage [ 17/Nov/09 ]

No after talking with the team we realized that the code is not needed and should have been removed. It was there to "fix" a problem but at some point the real problem was fixed so this is no longer needed.

Comment by Jonathan H. Wage [ 17/Nov/09 ]

I committed some changes, can you test those? Also, can you get on IRC or something where we can chat so we can get this issue fixed today?





[DC-39] Linking between one to many relations with synchronizeWithArray fails Created: 18/Sep/09  Updated: 02/Nov/09  Resolved: 02/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Relations
Affects Version/s: 1.0.12, 1.1.4, 1.2.0-ALPHA1
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Blocker
Reporter: Marcus Häußler Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

tested on
PHP Version 5.2.6-3ubuntu4.2, PHP Version 5.3
MySQL, PgSQL
Doctrine Version 1.0.11 Revision: 6380
Doctrine Version 1.1.3 Revision: 6380
Doctrine Version 1.1.4 Revision: 6409
Doctrine Version 1.2


Attachments: File DC39TestCase.php     File example.php    

 Description   

Linking between one to many relations with synchronizeWithArray() has a strange behavior.

Example (fully example is in the attachment):
Group has many Users
User has one Group

When I have a group-object (id 2) and do the following:

$group->synchronizeWithArray(array(
	'Users' => array(1,2)
));
$group->save();

on the first execute of the script the users with id 1 and 2 are linked to group 2 (with foreign key = group_id in user table) -> right
on the second execute of the script the users with id 1 and 2 are linked to null -> failure
on the third execute of the script the users with id 1 and 2 are linked to group 2 -> right
on the fourth execute of the script the users with id 1 and 2 are linked to null -> failure
and so on

I tried to find the error on my self, but had no luck.
That's what I have found:
On every script-execution the relations to group 2 are first nulled.
If they were allready null für user 1 and 2, the relations are build with an update -> right!; but when this two users had allready this relation they are only nulled and no update is processed.
Thats why there is this strange toggling on the foreign key on every script execution.

Maybe it has something to do with the record_state which is clean, when the relations are allready set in the DB -> no update is executed, but the nulling of all foreign key linked to group 2.



 Comments   
Comment by Marcus Häußler [ 28/Sep/09 ]

I changed the code on record.php near line 1923 to

 
                if (is_array($value)) {
                    if (isset($value[0]) && ! is_array($value[0])) {
                        $this->unlink($key, array(), true); // parameter set to true
                        foreach ($value as $id) {
                            $this->link($key, $id, true); // parameter set to true
                        }
                    } else {
                        $this->$key->synchronizeWithArray($value);
                    }
                }

With this changed parameters the described bug does not appear, cause the whole state-checking (in UnitOfWork->saveGraph()) is not used and the querys are submitted emidiatly.

Of course this can not be the way, but I hope it helps you a bit to find the error and others who need the synchronizeWithArray method working now.

Comment by Jonathan H. Wage [ 06/Oct/09 ]

Have you tried producing a test case for this? When I tested it I was not able to produce the same behavior in Doctrine standalone. Does this happen in your project or did you try outside of your project with just Doctrine?

Comment by Marcus Häußler [ 07/Oct/09 ]

I tested this with doctrine as a standalone.

Have you looked at the database entries with an external query-browser or have you just looked at the objects?
The doctrine_records/collections are build right while the database entries can act with the described behavior.

I will try to build a testcase but tell me wether you looked in the database to recognize the behavior.

Comment by Marcus Häußler [ 07/Oct/09 ]

Testcase uploaded.





[DC-366] Error with tokenizer for JOINs (comments include proposed solutions) Created: 18/Dec/09  Updated: 02/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.2.0
Fix Version/s: 1.2.2

Type: Bug Priority: Critical
Reporter: Christian Seaman Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 1
Labels: None
Environment:

Symfony-1.3, reporting below is based on the symfony-1.3.1 sandbox, but same problem occurs in other (non-sandbox) symfony-1.3 environments


Attachments: Text File jira-ticket-dc366.patch     File schema.yml    

 Description   

Using the attached schema.yml works fine with Symfony-1.2 and Doctrine-1.0. It even works when I have tested it with Symfony-1.2 and Doctrine-1.1.

However, when using Symfony-1.3 and Doctrine-1.2 the following happens:

 
> php symfony doctrine:build-all-reload
>> doctrine  Dropping "doctrine" database
>> doctrine  Creating "dev" environment "doctrine" database
>> doctrine  generating model classes
>> file+     C:\Users\XXXXXXXXXXXXXXXX\AppDa...\Temp/doctrine_schema_30398.yml
>> tokens    C:/web/sf_sandbox-1.3/lib/model/doctrine/base/BaseBar.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/model/doctrine/base/BaseFoo.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/model...e/base/BaseJoinFooBar.class.php
>> autoload  Resetting application autoloaders
>> file-     C:/web/sf_sandbox-1.3/cache/fro.../config/config_autoload.yml.php
>> doctrine  generating form classes
>> tokens    C:/web/sf_sandbox-1.3/lib/form/BaseForm.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/form/doctrine/BarForm.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/form/...rine/base/BaseBarForm.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/form/...rine/base/BaseFooForm.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/form/...se/BaseJoinFooBarForm.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/form/...rine/BaseFormDoctrine.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/form/doctrine/FooForm.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/form/doctrine/JoinFooBarForm.class.php
>> autoload  Resetting application autoloaders
>> file-     C:/web/sf_sandbox-1.3/cache/fro.../config/config_autoload.yml.php
>> doctrine  generating filter form classes
>> tokens    C:/web/sf_sandbox-1.3/lib/filte...octrine/BarFormFilter.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/filte...ase/BaseBarFormFilter.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/filte...ase/BaseFooFormFilter.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/filte...eJoinFooBarFormFilter.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/filte...aseFormFilterDoctrine.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/filte...octrine/FooFormFilter.class.php
>> tokens    C:/web/sf_sandbox-1.3/lib/filte.../JoinFooBarFormFilter.class.php
>> autoload  Resetting application autoloaders
>> file-     C:/web/sf_sandbox-1.3/cache/fro.../config/config_autoload.yml.php
>> doctrine  generating sql for models
>> doctrine  Generated SQL successfully for models
>> doctrine  created tables successfully
>> doctrine  Loading data fixtures from "C:\web\sf_sandbox-1.3\data/fixtures"


  Couldn't find class FooBar

The attached schema.yml looks like this:

# /config/doctrine/schema.yml
Foo:
  columns:
    id:
      type:                    integer(8)
      primary:                 true
      autoincrement:           true
    foo_field:                 string(100)
  relations:
    Bars:
      class:                   Bar
      refClass:                JoinFooBar
      local:                   foo_id
      foreign:                 bar_id
Bar:
  columns:
    id:
      type:                    integer(8)
      primary:                 true
      autoincrement:           true
    bar_field:               string(30)
JoinFooBar:
  columns:
    foo_id:
      type:                    integer(8)
      primary:                 true
    bar_id:
      type:                    integer(8)
      primary:                 true

As you can see, there is not meant to be any class called FooBar (the reference class for the many-to-many join is called JoinFooBar) so where is the name "FooBar" being picked up from and why is the code complaining that it cannot be found?

The fixture file is empty so there shouldn't be anything causing problems there.

This bug is making it impossible to upgrade our existing projects to Symfony-1.3 + Doctrine-1.2 so I'd be most grateful if you could look into this.

If the schema is changed from:

...
    bar_field:               string(30)
JoinFooBar:
  columns:
...

To:

...
    bar_field:               string(30)
FooBar:
  columns:
...

it seems to work, (that error disappears - even though the refClass is still set to *Join*FooBar) but we cannot easily justify changing all the classnames of all our Join tables in the projects we want to upgrade!

I hope you can see some simple solution to this and I'm happy to answer any questions you have.

(To reproduce this bug use the symfony sandbox, create a database and then use the attached schema.yml file.)

C



 Comments   
Comment by Christian Seaman [ 04/Jan/10 ]

As reported here:
http://forum.symfony-project.org/index.php/t/24441/

It seems that the problem is with the doctrine:build-all-reload in symfony and not anything deeper.

As such, I think it would make sense to disactivate that task in symfony (rather than marking it as deprecated) since it is broken and a note in it directing people to use the new tasks would be far more useful.

C

Comment by Christian Seaman [ 04/Jan/10 ]

As noted above, this is not a Critical error with Doctrine, but rather a problem with a symfony task.

Comment by Christian Seaman [ 17/Jan/10 ]

On further inspection, this is not an error with the symfony task, but a problem with the Tokenizer class, in particular where Doctrine_Query_From::parse() calls Doctrine_Query_Tokenizer::bracketExplode() with the delimiter set to 'JOIN'.

Comment by Christian Seaman [ 17/Jan/10 ]

OK... I think I have found and solved this one but a more experienced member of the Doctrine team should review what I propose before adding it to the codebase.

The problem occurs because Doctrine_Query_Tokenizer::getSplitRegExpFromArray() is being passed a string with no word boundaries (the parameter being passed to it by Doctrine_Query_From::parse() is "JOIN"). getSplitRegExpFromArray() then treats this string as a case insensitive regex so if any of your class or field names contain this string they are treated as a split.

E.g. "JoinFooBar JOIN BanjoIndia" would be split into array ("", "FooBar", "Ban", "dia").

This is clearly wrong and would mean that no table or fieldnames could contain the letters j-o-i-n in that order.

The proposed solution is as follows:

Current version of Doctrine_Query_Tokenizer::getSplitRegExpFromArray() (Doctrine 1.2, as of r7034):

 
    private function getSplitRegExpFromArray(array $d){
        $d = array_map('preg_quote', $d);

        if (in_array(' ', $d)) {
            $d[] = '\s';
        }

        return '#(' . implode('|', $d) . ')#';
    }

Proposed modification checks each delimiter given. If that delimiter consists only of \w characters (i.e. [0-9a-zA-Z_]) then a word boundary is required before and after that delimiter if it's going to be used as a match:

 
    private function getSplitRegExpFromArray(array $d){
        foreach ($d as $key => $string) {
            $escapedString = preg_quote($string);
            if (preg_match('#^\w+$#', $string)) $escapedString = "\W$escapedString\W";
            $d[$key] = $escapedString;
        }

        if (in_array(' ', $d)) {
            $d[] = '\s';
        }

        return '#(' . implode('|', $d) . ')#';
    }

Now, this seems to work for me in brief testing for my own purposes. However, the test cases in TokenizerTestCase.php (particularly testBracketExplode()) are far from exhaustive so I'm not sure if this proposed solution would suit all cases. E.g. do you ever need the delimiter to match at the very beginning or end of a string? At the moment it would not match but you could deal with this by using this instead:

 if (preg_match('#^\w+$#', $string)) $escapedString = "(^|\W)$escapedString($|\W)";

An alternative solution, but far less robust, would be just to modify Doctrine_Query_From::parse() from

    public function parse($str, $return = false)
    {
        $str = trim($str);
        $parts = $this->_tokenizer->bracketExplode($str, 'JOIN');

        $from = $return ? array() : null;
...

to this, with spaces around the JOIN string passed to bracketExplode():

    public function parse($str, $return = false)
    {
        $str = trim($str);
        $parts = $this->_tokenizer->bracketExplode($str, ' JOIN ');

        $from = $return ? array() : null;
...

This is probably going to run marginally faster, but it leaves the risk that some change in future will bring up the same problem again, so the former (fixed regexp) solution would seem to be better for stability.

I hope you can pick this up, review it and implement the most suitable change (and update the test cases too) - at the moment this is a big bug since any schema which defines table or fieldnames that contain the consecutive letters j-o-i-n will break.

C

Comment by Matthias Steinböck [ 18/Jan/10 ]

I found the same bug.

The error i got was "Couldn't find class ed". at first i wondered where i used "ed" but i did nowhere. the code i used was:

$from = 'Media';
$alias = 'Content';

$qry = Doctrine_Query::create();
$qry->from("$from orig");
$qry->leftJoin("orig.$alias joined"); // here the error occoures using "joined"

I located the Bug in Doctrine_Query_From using $this->_tokenizer->bracketExplode for checking the right arm of the join so i only can confirm this bug.

Comment by Christian Seaman [ 19/Jan/10 ]

Matthias,

feel free to use the fix detailed above. I have been using this in my local copy of Doctrine and it seems to work well so far.

We just need a member of Doctrine's dev team to decide which of the fixes above makes most sense and then to update the code for the next Doctrine release.

The fix I am using at the moment is the first one:

          if (preg_match('#^\w+$#', $string)) $escapedString = "\W$escapedString\W";
Comment by Jonathan H. Wage [ 01/Mar/10 ]

Hi, before I can test your proposed solution. I need to see a patch with your changes. I can't very easily and reliably copy and paste your changes from the comments.

Comment by Christian Seaman [ 02/Mar/10 ]

Hi Jon,

Thanks for looking into this.

I will generate a patch and attach it to this ticket for your review.

Feel free to rip it apart and change the test cases or regex used.

C

Comment by Christian Seaman [ 02/Mar/10 ]

Patch with suggested fix for the tokenizer and basic test case.





[DC-337] Doctrine needs support for union all Created: 08/Dec/09  Updated: 03/Mar/10  Resolved: 03/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.2.1
Fix Version/s: None

Type: Bug Priority: Critical
Reporter: Chris F Assignee: Guilherme Blanco
Resolution: Won't Fix Votes: 1
Labels: None
Environment:

Mac Snow Leopard, Win XP
PHP, MySql



 Description   

The following query cannot be retrieved as objects. The following will work with ->fetchAll(). However, the result set will return as an array. I need this to be as an object.

return Doctrine_Manager::getInstance()>getCurrentConnection()>fetchAll("

SELECT

v1.*

FROM (
SELECT
'song_comment' as user_action,
null as artist_id, user_id, song_id, null as video_id, null as event_id, null as ip_address, null as is_going,
comment, created_at
FROM tbl_user_song_comment
UNION ALL
SELECT
'videocomment' as user_action,
null as artist_id, user_id, null as song_id, video_id, null as event_id, null as ip_address, null as is_going,
comment, created_at
FROM tbl_user_video_comment
UNION ALL
SELECT
'event_comment' as user_action,
null as artist_id, user_id, null as song_id, null as video_id, event_id, null as ip_address, null as is_going,
comment, created_at
FROM tbl_user_event_comment
) AS v1

ORDER BY created_at DESC

");

In summary, what I am trying to do is select all comments from tbl_user_song_comment, tbl_user_video_comment and tbl_user_event_comment and order by date (created_at).

The following ticket at http://trac.doctrine-project.org/ticket/18 should have been implemented!
There is no way in Doctrine to ->select() a view. In this case 'v1', since ->from() only expects a class!



 Comments   
Comment by Guilherme Blanco [ 03/Mar/10 ]

Branch 1.2 is our last branch in 1.X series and we do not expect to have any other enhancements so far.
Marking this as won't fix, since we're not planning new middle point releases for 1.X series.





[DC-333] Doctrine_Migration_Diff reuses the same temporary folder on consecutive runs, resulting in collisions between projects Created: 07/Dec/09  Updated: 07/Dec/09  Resolved: 07/Dec/09

Status: Closed
Project: Doctrine 1
Component/s: Migrations
Affects Version/s: 1.2.0
Fix Version/s: 1.2.1

Type: Bug Priority: Critical
Reporter: Tom Boutell Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Symfony 1.3 with MacPorts PHP 5.3.1



 Description   

svn co http://svn.symfony-project.com/plugins/pkContextCMSPlugin/sandbox/branches/1.3 cmstest13
cd cmstest13
[edited config/doctrine/schema.yml and added a trivial table so there would be something at the app level]
[successful doctrine:build --all followed]

./symfony doctrine:generate-migrations-diff
>> doctrine generating migration diff
>> file+ /private/var/folders/3H/3Hu3TTyjFt...TI/Tmp/doctrine_schema_15549.yml

Fatal error: Class 'EventUser' not found in /private/var/folders/3H/3Hu3TTyjFtuvtN3D5tDUxU+++TI/Tmp/fromprfx_doctrine_tmp_dirs/base/BaseEventGuest.class.php on line 7

I recognize my personal temp folder from my environment in there:

TMPDIR=/var/folders/3H/3Hu3TTyjFtuvtN3D5tDUxU+++TI/Tmp/

So presumably these tasks are supposed to clean it up after they use it. But none of my attempts to use this task so far have succeeded, so I suspect the problem is that the folder does not get cleaned up in the event of an error. This folder needs to get cleaned up on all errors, or perhaps cleared at the start of a new run (that is probably going to turn out to be a more reliable fix).

I'll manually clear it and move on to the bug I was originally looking to reproduce.



 Comments   
Comment by Jonathan H. Wage [ 07/Dec/09 ]

Hmm. When I look at Doctrine_Migration_Diff we implement a _cleanup() method that is for that purpose. Does it not clean up the directory properly?

Comment by Tom Boutell [ 07/Dec/09 ]

[Peeks at source]

Looks like you do it last. If an exception is thrown it doesn't happen (I just verified that I have a full folder of classes left behind after an attempt to use it). Then you have a lingering problem confounding your attempts to try again.

Suggest you call _cleanup() at the start and the end. The first call won't take much time at all if the last run was a happy one. If it was an unhappy one you really need it.

  • * *

A much more minor issue:

I'm a little nervous about the fact that if I were running two schema diffs for two different projects at once, they would still collide, sharing the same tmp folder. I would suggest starting everything from TMP/doctrine-$pid where $pid = getpid() or something like that.

In pkToolkit we use SF_ROOT_DIR/data/pk_writable/tmp because that is safely project-specific.

Comment by Jonathan H. Wage [ 07/Dec/09 ]

Tom, as you have an environment setup with the problem exposed, could you prepare a patch that fixes the problems you are encountering?

Comment by Jonathan H. Wage [ 07/Dec/09 ]

So I just want to confirm. We have two issues now. The _cleanup() method needs to be called when it starts. This patch should take care of that:

Index: lib/Doctrine/Migration/Diff.php
===================================================================
--- lib/Doctrine/Migration/Diff.php	(revision 6882)
+++ lib/Doctrine/Migration/Diff.php	(working copy)
@@ -93,6 +93,8 @@
      */
     public function generateChanges()
     {
+        $this->_cleanup();
+
         $from = $this->_generateModels(self::$_fromPrefix, $this->_from);
         $to = $this->_generateModels(self::$_toPrefix, $this->_to);

Now we have another issue where the paths could conflict. Can we open another ticket to work on that issue? Can you confirm that the above patch fixes this individual issue?

Comment by Tom Boutell [ 07/Dec/09 ]

Yes that is the correct patch, I just prepared the exact same patch and went back to my email to find the ticket and saw your comment.

I will open a separate ticket re: the potential clash between projects. It's certainly less probable but it doesn't make sense for them to contend for a single folder.

Thanks!

Comment by Jonathan H. Wage [ 07/Dec/09 ]

Cool. Yes I think we can fix the other issue but in another revision/ticket. I will go ahead and commit that patch and close this ticket.

Thanks, Jon





[DC-316] Model classes aren't loaded anymore when migrating to 1.2 Created: 03/Dec/09  Updated: 30/Dec/09  Resolved: 07/Dec/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.0
Fix Version/s: None

Type: Bug Priority: Critical
Reporter: aiso haikens Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Mac os, leopard 10.5. I use conservative model loading and autoload table classes.


Attachments: Text File ff.txt    

 Description   

When migrating from doctrine 1.1.0 to 1.2 it fails to load the model classes anymore. It complains it cannot find the model class 'Building' when doing a Doctrine::getTable('Building')->findAll(). See attached backtrace. After hours of digging in the code and countless debug statements I found out that the automatic loading of the model classes is removed (for some good reason?) from the doctrine autoloader(). This will off course give exceptions for people depending on this mechanism!

It seems that the solution is to add another spl_autoload_register(array('Doctrine','modelsAutoload')); to the bootstrapper (apart from the normal spl_autoload_register(array('Doctrine','autoload'));

But the strangest thing is: I could not find any information about this, although this is (I would say) VERY critical information for people depending on auto model class loading and would like to keep it working! So I would suggest to put this critical information into the ('migration' or 'what is new') documentation of 1.2 because I could not find it. Yes, there is something about PEAR like model loading, but that is not what I want, I would like to keep my app still working after migrating to 1.2.



 Comments   
Comment by Jonathan H. Wage [ 07/Dec/09 ]

I added some information about this to the upgrade file. Thanks for reporting it and sorry about the missing information.

Comment by Alfredo Beaumont [ 30/Dec/09 ]

I had the same problem, but I was not migrating but trying doctrine for the first time. I suggest you to modify the "Doctrine ORM for PHP" document for 1.2 since it doesn't talk about this issue and it's rather frustrating to see how the generate.php doesn't work at all for no aparent reason (no error, no warning). I also had to dig in the code for some hours, which is not something that should be expected on a first aproach... and may give a bad impression to many newcomers.





[DC-205] Problem with serial fields on PostgreSQL Created: 10/Nov/09  Updated: 10/Nov/09  Resolved: 10/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Critical
Reporter: Antonio J. Garcia Lagar Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PHP 5.2.3
PostgreSQL 8.1



 Description   

When a new record is inserted into a table with an autoincrement primary key, the function Doctrine_Connection_UnitOfWork::processSingleInsert is called with the record to insert as parameter.

In Doctrine 1.1.x (http://trac.doctrine-project.org/browser/branches/1.1/lib/Doctrine/Connection/UnitOfWork.php#L590) this method was the responsible for getting the new ID value from the sequence, and with this value, it MODIFIED THE ARRAY OF FIELD VALUES to be inserted into the table.

Now this is done at a protected method named _assignSequence (http://trac.doctrine-project.org/browser/branches/1.2/lib/Doctrine/Connection/UnitOfWork.php#L629) which assigns the identifier to the record, but DOES NOT MODIFY THE ARRAY OF VALUES to be send to the database for the insert so when my db receive a null value for the ID column, generate a new one from the sequence.

The result is that the record gets an identifier which is different from the one that it really has on the database.

An example: on a db with a table 'foo' with two columns, 'id' and 'name', and a sequence called 'foo_id_seq' with a value of 6, when I try to insert a record with a named 'bar', the function $this->conn->insert($table, $fields); at http://trac.doctrine-project.org/browser/branches/1.1/lib/Doctrine/Connection/UnitOfWork.php#L595 receive as parameters 'foo' and array('id' =>7, 'name' =>'bar')

In Doctrine 1.2 the function at http://trac.doctrine-project.org/browser/branches/1.2/lib/Doctrine/Connection/UnitOfWork.php#L630 recevie as parameters 'foo' and array('name' =>'bar')

(Sorry for my poor English)



 Comments   
Comment by Antonio J. Garcia Lagar [ 10/Nov/09 ]

This error is a consecuence of the changeset 6635 (http://trac.doctrine-project.org/changeset/6635/branches/1.2/lib/Doctrine/Connection/UnitOfWork.php)

Comment by Jonathan H. Wage [ 10/Nov/09 ]

Thanks for the ticket. I committed a fix that will be in BETA2. Could you test and confirm that it fixes the issue?





[DC-189] When applying changes to n:n relations that contain partially same data DELET is not fired Created: 04/Nov/09  Updated: 17/Nov/09  Resolved: 17/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Relations
Affects Version/s: 1.2.0-BETA1, 1.2.0-BETA2
Fix Version/s: 1.2.0-RC1

Type: Bug Priority: Critical
Reporter: Jaanus Heeringson Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Error introduced in revision 6611



 Description   

When changing n:n relations in a way that the new dataset contains relations that were present in the previous state (as in adding a relation to existing ones) DELETE is not fired before insert is done. In the example below I simply reapply an existing relation. This is done by Record::synchronizeWithArray().

Result:

Doctrine_Connection_Mysql_Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '4-14' for key 'PRIMARY'

SQL Query pre r6611:
6 Query START TRANSACTION
6 Query UPDATE `structure` SET `user_create_id` = NULL, `user_modify_id` = NULL, `updated_at` = '2009-11-04 23:38:02' WHERE `id` = '4'
6 Query DELETE FROM `structure_category` WHERE (`structure_id` = '4')
6 Query INSERT INTO `structure_category` (`category_id`, `structure_id`) VALUES ('5', '4')
6 Query COMMIT

SQL QUERY with r6611:
5 Query START TRANSACTION
5 Query UPDATE `structure` SET `user_create_id` = NULL, `user_modify_id` = NULL, `updated_at` = '2009-11-04 23:36:33' WHERE `id` = '4'
5 Query INSERT INTO `structure_category` (`category_id`, `structure_id`) VALUES ('5', '4')
5 Query ROLLBACK



 Comments   
Comment by Jaanus Heeringson [ 04/Nov/09 ]

Added 1.2.0-BETA2

Comment by Jonathan H. Wage [ 16/Nov/09 ]

Can you show the code you're using? a test case of some sort. It is really hard to fix the problem with so little information

Comment by Jaanus Heeringson [ 16/Nov/09 ]

This is quite a complex project so I'll try as best as I can.
What is happening here is that I'm adding another category (id:28) to the object (in this case an entry) that allready has one existing category (id: 10). The primary Id's are named - id!

The Code
	public function setJsonData($query,$data){
		$_query=$this->primaryQuery($query,self::RELATIONS_FULL); //generates DQL query - not relevant
		$_record=$_query->getOne(array(),2); //Fetches the existing record from DQL query
		$data=$this->fromJsonData($data,$query); //Cleans up the recieved JSON data and returns an array
		ss_error::log($data,'In data'); //Data output 1 - incoming data
		ss_error::log($_record->toArray(),'Existing data'); //Data output 2 - record contents
		$_record->synchronizeWithArray($data,true);//Synchronize
		ss_error::log($_record->toArray(),'Merged data'); //Data output 3 - resulting datac
		$_record->save(); //#ERROR#
		return $_record->toArray(true);
	}
Data output 1 - incoming, cleaned up data
array (
  'id' => '5',
  'active' => true,
  'timedpub' => true,
  'slug' => 'how_we_work',
  'date_pub' => NULL,
  'date_rej' => NULL,
  'UserCreate' => NULL,
  'UserModify' => NULL,
  'Category' => 
  array (
    0 => '10',
    1 => '28',
  ),
  'User' => 
  array (
  ),
  'Translation' => 
  array (
    'en' => 
    array (
      'headline' => 'How we work',
      'name' => 'how we work',
      'teaser' => NULL,
      'text' => '...',
      'lang' => 'en',
      'id' => '5',
    ),
    'sv' => 
    array (
      'headline' => 'Så arbetar vi',
      'name' => 'Så arbetar vi',
      'teaser' => '<br />',
      'text' => '...',
      'lang' => 'sv',
      'id' => '5',
    ),
  ),
  'user_create_id' => NULL,
  'user_modify_id' => NULL,
)
Data output 2 - record contents
array (
  'id' => '5',
  'active' => true,
  'timedpub' => true,
  'slug' => 'how_we_work',
  'date_pub' => NULL,
  'date_rej' => NULL,
  'user_create_id' => NULL,
  'user_modify_id' => NULL,
  'created_at' => '2009-11-12 01:41:36',
  'updated_at' => '2009-11-12 01:41:36',
  'Category' => 
  array (
    0 => 
    array (
      'id' => '10',
      'slug' => 'arbetsmetod',
      'path' => '/om_hamilton/arbetsmetod',
      'parent_id' => NULL,
      'owner_id' => '8',
      'public' => true,
      'created_at' => '2009-11-12 01:41:38',
      'updated_at' => '2009-11-12 01:41:38',
      'Translation' => 
      array (
        'sv' => 
        array (
          'id' => '10',
          'name' => 'arbetsmetod',
          'headline' => 'Vår arbetsmetod',
          'lang' => 'sv',
        ),
      ),
    ),
  ),
  'User' => 
  array (
  ),
  'Translation' => 
  array (
    'en' => 
    array (
      'id' => '5',
      'headline' => 'How we work',
      'name' => 'how we work',
      'teaser' => NULL,
      'text' => '...',
      'lang' => 'en',
    ),
    'sv' => 
    array (
      'id' => '5',
      'headline' => 'Så arbetar vi',
      'name' => 'Så arbetar vi',
      'teaser' => '<br />',
      'text' => '...',
      'lang' => 'sv',
    ),
  ),
)
Data output 3 - result after Synchronize
array (
  'id' => '5',
  'active' => true,
  'timedpub' => true,
  'slug' => 'how_we_work',
  'date_pub' => NULL,
  'date_rej' => NULL,
  'user_create_id' => NULL,
  'user_modify_id' => NULL,
  'created_at' => '2009-11-12 01:41:36',
  'updated_at' => '2009-11-12 01:41:36',
  'Category' => 
  array (
    0 => 
    array (
      'id' => '10',
      'slug' => 'arbetsmetod',
      'path' => '/om_hamilton/arbetsmetod',
      'parent_id' => NULL,
      'owner_id' => '8',
      'public' => true,
      'created_at' => '2009-11-12 01:41:38',
      'updated_at' => '2009-11-12 01:41:38',
      'Translation' => 
      array (
        'sv' => 
        array (
          'id' => '10',
          'name' => 'arbetsmetod',
          'headline' => 'Vår arbetsmetod',
          'lang' => 'sv',
        ),
      ),
    ),
    1 => 
    array (
      'id' => '28',
      'slug' => 'att_arbeta_hos_oss',
      'path' => '/karriar/arbeta_hos_oss',
      'parent_id' => NULL,
      'owner_id' => '21',
      'public' => true,
      'created_at' => '2009-11-12 01:41:39',
      'updated_at' => '2009-11-12 01:41:39',
    ),
  ),
  'User' => 
  array (
  ),
  'Translation' => 
  array (
    'en' => 
    array (
      'id' => '5',
      'headline' => 'How we work',
      'name' => 'how we work',
      'teaser' => NULL,
      'text' => '...',
      'lang' => 'en',
    ),
    'sv' => 
    array (
      'id' => '5',
      'headline' => 'Så arbetar vi',
      'name' => 'Så arbetar vi',
      'teaser' => '<br />',
      'text' => '...',
      'lang' => 'sv',
    ),
  ),
)
The error
'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '5-10' for key 'PRIMARY''
Comment by Jonathan H. Wage [ 16/Nov/09 ]

Is it possible for you to make an actual test case? That way I can just execute it and troubleshoot the problem very fast.





[DC-146] GenerateMigrationsDiff task does not use new order of changeColumn() Created: 27/Oct/09  Updated: 30/Oct/09  Resolved: 30/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: Migrations
Affects Version/s: 1.2.0-ALPHA3
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Critical
Reporter: Dennis Benkert Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: File Builder.php.diff    

 Description   

The GenerateMigrationsDiff task generates migrations which still use the old ordering of parameters of changeColumn().

This is how it gets generated:

$this->changeColumn('my_table', 'my_column', '25', 'timestamp', array(
'notnull' => '1',
));

Why it should be like this

$this->changeColumn('my_table', 'my_column', 'timestamp', '25', array(
'notnull' => '1',
));

I also added a patch to fix this.






[DC-145] Invalid parameter number: number of bound variables does not match number of tokens Created: 27/Oct/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.0.13, 1.1.4
Fix Version/s: 1.0.14, 1.1.6, 1.2.0-BETA3

Type: Bug Priority: Critical
Reporter: Amir W Assignee: Guilherme Blanco
Resolution: Fixed Votes: 8
Labels: None

Attachments: GIF File ScreenHunter_01 Nov. 16 17.50.gif    

 Description   

Please see description posted on Doctrine's group:
http://groups.google.com/group/doctrine-user/browse_thread/thread/6cc308526e5ab075



 Comments   
Comment by Jonathan H. Wage [ 27/Oct/09 ]

Possible to give some more information? Code you're using to produce the error. We need to be able to produce the issue with some code in order to fix it. If you could make a test case that will help us. Otherwise it is very difficult to fix an issue blindly Thanks. Something that also helps is singling out the revision that caused the problem.

Comment by Bill Hunt [ 27/Oct/09 ]

I've discovered the same issue, with the symfony doctrine plugin Revision 23394. I just updated to the latest version and a "andWhereNotIn" clause which worked perfectly before is now failing -

$q->andWhereNotIn('hr.providerid', $ignoreProviderIds);

where $ignoreProviderIds = array('51', '31');

The stack trace is making it look like it's repeating the parameters somehow? Note the "'51', '31', '51', '31'" line below...

  1. at ()
    in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Connection.php line 1086 ...

1083.
1084. $name = 'Doctrine_Connection_' . $this->driverName . '_Exception';
1085.
1086. $exc = new $name($e->getMessage(), (int) $e->getCode());
1087. if ( ! isset($e->errorInfo) || ! is_array($e->errorInfo))

{ 1088. $e->errorInfo = array(null, null, null, null); 1089. }
  1. at Doctrine_Connection->rethrowException(object('PDOException'), object('Doctrine_Connection_Statement'))
    in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Connection/Statement.php line 253 ...

250. } catch (Doctrine_Adapter_Exception $e)

{ 251. }

252.
253. $this->_conn->rethrowException($e, $this);
254.
255. return false;
256. }

  1. at Doctrine_Connection_Statement->execute(array('51', '31', '51', '31'))
    in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Connection.php line 1014 ...

1011. try {
1012. if ( ! empty($params))

{ 1013. $stmt = $this->prepare($query); 1014. $stmt->execute($params); 1015. 1016. return $stmt; 1017. }

else

{ # at Doctrine_Connection->execute('SELECT DISTINCT h6.hotelid, COUNT(h10.hotelid) AS h10__0 FROM hotel h6 LEFT JOIN hotelDetails h7 ON h6.hotelid = h7.hotelid LEFT JOIN hotelProvider h8 ON h6.hotelid = h8.hotelid LEFT JOIN hotelPriceDetails h9 ON h6.hotelid = h9.hotelid LEFT JOIN location l4 ON h6.locationid = l4.locationid LEFT JOIN location l5 ON h6.locationid = l5.locationid LEFT JOIN locationAdmin1Code l6 ON l5.admin1codeid = l6.locationadmin1codeid LEFT JOIN hotelRating h10 ON h6.hotelid = h10.hotelid WHERE h6.hotelrating >= 3.0 AND h6.hotelrating < 5 AND h6.hotellatitude IS NOT NULL AND h6.hotellatitude != 0 AND h6.hotellongitude IS NOT NULL AND h6.hotellongitude != 0 AND h9.hotelavgminprice < 500 AND h6.hotelstars >= 2 AND h6.locationid = 33033 AND h10.providerid NOT IN (?, ?) GROUP BY h6.hotelid HAVING h10__0 > 0 ORDER BY h6.hotelrating desc LIMIT 3', array('51', '31', '51', '31')) in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Query.php line 1155 ... 1152. $this->useQueryCache(false); 1153. 1154. // mysql doesn't support LIMIT in subqueries 1155. $list = $this->_conn->execute($subquery, $this->getParams($params))->fetchAll(Doctrine::FETCH_COLUMN); 1156. $subquery = implode(', ', array_map(array($this->_conn, 'quote'), $list)); 1157. 1158. break; # at Doctrine_Query->getSqlQuery(array('51', '31')) in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Query/Abstract.php line 977 ... 974. }

975. }
976. } else

{ 977. $query = $this->getSqlQuery($params); 978. }

979. } else

{ 980. $query = $this->_view->getSelectSql(); # at Doctrine_Query_Abstract->_execute(array('51', '31')) in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Query/Abstract.php line 1036 ... 1033. $result = $this->_constructQueryFromCache($cached); 1034. }

1035. } else {
1036. $stmt = $this->_execute($params);
1037.
1038. if (is_integer($stmt)) {
1039. $result = $stmt;

  1. at Doctrine_Query_Abstract->execute()
    in SF_ROOT_DIR/apps/frontend/modules/common/actions/components.class.php line 1129 ...
Comment by Bill Hunt [ 27/Oct/09 ]

Here's a diff of the changes that seem to be problematic:

sfDoctrinePlugin/lib/doctrine/Doctrine/Query.php

< * $Id: Query.php 6564 2009-10-23 18:21:16Z jwage $

> * $Id: Query.php 6407 2009-09-24 21:38:36Z guilhermeblanco $
329,330d328
< } else if ( ! ($this->_conn->getAttribute(Doctrine::ATTR_PORTABILITY) & Doctrine::PORTABILITY_EXPR)){
< return $dqlAlias;
1155c1153
< $list = $this->_conn->execute($subquery, $this->getParams($params))->fetchAll(Doctrine::FETCH_COLUMN);

> $list = $this->_conn->execute($subquery, $params)->fetchAll(Doctrine::FETCH_COLUMN);

Comment by Aurélien Appéré [ 04/Nov/09 ]

The problem comes from what Bill Hunt says.
Tha fact is that parameters ($params) are duplicated by function getParams($params).

Comment by Oncle Tom [ 05/Nov/09 ]

I also encouter it and it's really blocking (as exception is thrown, failing page to display).

The most "funny" things it does not always happen (even though I have it through sfDoctrinePager).
But clearly, I encountered it on parts of code I have not changed since months.

Comment by Eugeniy Belyaev [ 05/Nov/09 ]

For me it happens when I'm trying to 'limit' the query. Query is complicated and contains joins, 'where' conditions, grouping and 'havings'.
And now it fails with duplicating bound params. Right after last subversion update and only when 'limiting'.

Comment by Eugeniy Belyaev [ 05/Nov/09 ]

Oh. Forgot to say - I'm using 1.0 version (which comes with symfony 1.2)

Comment by Bill Hunt [ 05/Nov/09 ]

As a temporary fix, I've downgraded the file in question on my site until the bug is patched. This may help some of you:

svn update -r 6407 symfony/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Query.php

You may need to modify your path to suit your own needs, of course.

Comment by François Hucliez [ 06/Nov/09 ]

same problems since I have updated, yesterday (11/05).
I observe in the stack trace a parameters duplication, with a special effect when parameter value is zero (see "array(0, )") :

at Doctrine_Connection->execute('SELECT DISTINCT c3.id FROM contact c3 LEFT JOIN adresse_contact a2 ON c3.id = a2.contact_id LEFT JOIN etablissement e3 ON a2.etablissement_id = e3.id LEFT JOIN centre c4 ON a2.centre_id = c4.id LEFT JOIN email_contact e4 ON c3.id = e4.contact_id WHERE c3.non_valide = ? ORDER BY c3.nom, c3.prenom, c3.id LIMIT 16', array(0, ))
in SF_ROOT_DIR\lib\vendor\symfony\lib\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Query.php line 1155

I just add this comment to say - like Eugeniy- I'm using 1.0.13 version (Revision: 6645) wich comes with symfony 1.2.9DEV

Comment by Simon Gow [ 09/Nov/09 ]

I've got the same problem, which seems to only affect the query when a limit is applied. (same reasons as above).

I'd probably revert the revision, but specifically you can fix it with

in Query.php 1155 removing $this->getParams($params) to $params

$list = $this->_conn->execute($subquery, $params)->fetchAll(Doctrine::FETCH_COLUMN);

and moving $q = $this->getCountQuery();

from 1930 to 1937 after $params = $this->_conn->convertBooleans($params);

Comment by Eugeniy Belyaev [ 10/Nov/09 ]

I think it's critical, isn't it?

Comment by Eugeniy Belyaev [ 12/Nov/09 ]

This bug affects sympal too

Comment by Etienne VOILLIOT [ 16/Nov/09 ]

Some informations to solve the problem : $this->getParams($params) merge arrays, and values are duplicated

Comment by Jonathan H. Wage [ 16/Nov/09 ]

This was already fixed in all versions in SVN. The fix will be in the next scheduled releases.





[DC-134] Parse error in lib/Doctrine/Cache/Xcache.php (missing ;) and delete() should be deleteCache() (patch included) Created: 23/Oct/09  Updated: 23/Oct/09  Resolved: 23/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: Caching
Affects Version/s: 1.2.0-ALPHA3
Fix Version/s: 1.2.0-ALPHA3

Type: Bug Priority: Critical
Reporter: Reko Tiira Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File Doctrine_Cache_Xcache.patch    

 Description   

Missing ; in saveCache() function and delete method should also be named deleteCache as in other drivers.
This prevents xcache driver from working as well as compiling Doctrine to single PHP file. Patch included to fix the issue.






[DC-103] doctrine 1.0 not getting table correctly - huge bug - not usable Created: 13/Oct/09  Updated: 30/Oct/09  Resolved: 30/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: Record
Affects Version/s: 1.0.12
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Critical
Reporter: Nopcea Flavius Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 1
Labels: None
Environment:

WIN XP



 Description   

In the method coreSetRelated from Record.php for 1-1 relation the table is not obtained correctly!

if ($value !== self::$_null)

{ $relatedTable = $value->getTable(); $foreignFieldName = $relatedTable->getFieldName($rel->getForeign()); }

instead of

$relatedTable = $value->getTable();

you should put

$relatedTable = $rel->getTable();

This is a huge bug that can be fixed very easily so please fix is asap!

I can not deploy my project until this is fixed!

Thanks a lot!

I do not know if other versions are affected! I use symfony 1.2.9! Should I make a ticket also for Symfony!

You do a great job with doctrine! Great project! I really like it



 Comments   
Comment by Jonathan H. Wage [ 13/Oct/09 ]

This sounds like a bug in your own code. $value should be an instance of Doctrine_Record and it is not. Make sure you're code is not passing an array or invalid value through to coreSetRelated(). If you're using symfony, a common cause of this is that you have an embedded form that has the same name as your relationship. This can cause issues currently.

Comment by Nopcea Flavius [ 14/Oct/09 ]

Hi!

I am using symfony but I have a regular form! Not an embedded one!

I have like this:

$form->getObject()->setAuthorId($authorId);

and when I do a $form->save I get an error in that method when dealing with the author!

If I do a var_dump($value) it will not be an object but a string variable!

$relatedTable = $value->getTable();

I worked with previous versions of symfony/doctrine but once I upgraded to 1.2.9 it doesn't work anymore!

To me it seems that in the saving process Doctrine is not getting the correct $value object!

Comment by Nopcea Flavius [ 14/Oct/09 ]

Hi!

I am using symfony but I have a regular form! Not an embedded one!

I have like this:

$form->getObject()->setAuthorId($authorId);

and when I do a $form->save I get an error in that method when dealing with the author!

If I do a var_dump($value) it will not be an object but a string variable!

$relatedTable = $value->getTable();

I worked with previous versions of symfony/doctrine but once I upgraded to 1.2.9 it doesn't work anymore!

To me it seems that in the saving process Doctrine is not getting the correct $value object!

Comment by Olivier [ 23/Oct/09 ]

Quite same problem here.

My code worked fine with Symfony 1.2.7, but I have the same fatal error since 1.2.8. If I change $value to $rel, everything works fine.

I'm using embedded forms with Doctrine and I have another way to solve it :

  • With this, I've got the issue :
    $this->embedForm('contact_physique', $contactForm);
  • But no anymore with this :
    $this->embedForm('ContactPhysique', $contactForm);

contact_physique is a relationship in my schema.

I do not know if that "new behavior" comes from Doctrine or Symfony, but it may help with Nopcea Flavius' problem.

Regards





[DC-93] Calling refreshRelated causes hasOne records to be created in error Created: 08/Oct/09  Updated: 30/Oct/09  Resolved: 30/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: Relations
Affects Version/s: 1.1.4
Fix Version/s: 1.0.13, 1.1.5, 1.2.0-BETA1

Type: Bug Priority: Critical
Reporter: Justin Mazzi Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Linux


Attachments: GZip Archive Doctrine-1.1.4-Sandbox.tar.gz    

 Description   

Calling save() on a record, then refreshRelated(), then save() again will cause hasOne rows to be generated in error. I've attached a Doctrine sandbox with everything you need to reproduce it. Below is a summary.

schema.yml

schema.yml
 
---
Staff:
  columns:
    username: string(50)
    password: string(255)
    active:
      type: boolean
      default: true
  indexes:
    user_pass_active_idx:
      fields: [username, password, active]


Tickets:
  columns:
    mask:
      unique: true
      type: string(10)
    staff_id: integer(9)
  relations:
    Staff:
      local: staff_id
      foreign: id
Test.php
 
<?php
$ticket = new Tickets();
$ticket->save();
$ticket->refreshRelated();
$ticket->save();

Queries that were run:

root@localhost on doctrine11sandbox
START TRANSACTION
INSERT INTO tickets (id, mask, staff_id) VALUES (NULL, NULL, NULL)
COMMIT
START TRANSACTION
*INSERT INTO staff (active) VALUES ('1')*
UPDATE tickets SET staff_id = '2' WHERE id = '2'
COMMIT


 Comments   
Comment by Justin Mazzi [ 08/Oct/09 ]

This seems to be enough to trigger it:

<?php
$ticket = new Tickets();
$ticket->refreshRelated();
$ticket->save();
Comment by Justin Mazzi [ 13/Oct/09 ]

I've tracked this down to fetchRelatedFor. This is the function creating the record:

LocalKey.php
<?php
/*
 *  $Id: LocalKey.php 5798 2009-06-02 15:10:46Z piccoloprincipe $
 *
 * 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.phpdoctrine.org>.
 */

/**
 * Doctrine_Relation_LocalKey
 * This class represents a local key relation
 *
 * @package     Doctrine
 * @subpackage  Relation
 * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @link        www.phpdoctrine.org
 * @since       1.0
 * @version     $Revision: 5798 $
 */
class Doctrine_Relation_LocalKey extends Doctrine_Relation
{
    /**
     * fetchRelatedFor
     *
     * fetches a component related to given record
     *
     * @param Doctrine_Record $record
     * @return Doctrine_Record|Doctrine_Collection
     */
    public function fetchRelatedFor(Doctrine_Record $record)
    {
        $localFieldName = $record->getTable()->getFieldName($this->definition['local']);
        $id = $record->get($localFieldName);

        if (is_null($id) || ! $this->definition['table']->getAttribute(Doctrine::ATTR_LOAD_REFERENCES)) {
            /* HERE */
            $related = $this->getTable()->create();





[DC-92] Doctrine_Import_Pgsql::listTableColumns() creates wrong default values for boolean fields Created: 08/Oct/09  Updated: 13/Oct/09  Resolved: 13/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.0-ALPHA1
Fix Version/s: 1.0.13, 1.1.5, 1.2.0-ALPHA3

Type: Bug Priority: Critical
Reporter: Maurice Makaay Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

When importing a db table as a model, we see the following for a boolean field:

        $this->hasColumn('is_blocked', 'boolean', 1, array(
             'type' => 'boolean',
             'length' => 1,
             'fixed' => false,
             'unsigned' => false,
             'notnull' => true,
             'default' => 'false',   // <----- this field not 0, 1 or a boolean, but a string literal linstead
             'primary' => false,
             ));

Creating an object and immediately saving it results in two validation errors for this field:

1. The field is not boolean, but string
2. The field is not length 1, but length 5 (string "false")

I applied the following patch to the listTableColumns() function:

            elseif (preg_match("/^'(.*)'::character varying$/", $description['default'], $matches)) {
                $description['default'] = $matches[1];
            }
+           elseif ($description['type'] == 'boolean') {
+               if ($description['default'] === 'true') {
+                   $description['default'] = true;
+               } elseif ($description['default'] === 'false') {
+                   $description['default'] = false;
+               }
+           }

            $columns[$val['field']] = $description;

This makes the import work as expected for us.






[DC-80] Doctrine/Import/Pgsql.php generates wrong default values for varchar fields Created: 06/Oct/09  Updated: 06/Oct/09  Resolved: 06/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.0-ALPHA1
Fix Version/s: 1.2.0-ALPHA2

Type: Bug Priority: Critical
Reporter: Maurice Makaay Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Ubuntu Linux, PostgreSQL 8.3, PHP 5.2.6



 Description   

We run a postgres database and have generated out base models from the database. In the base models, we see the following issue:

        $this->hasColumn('contractor_type', 'string', 150, array(
             'type' => 'string',
             'length' => '150',
             'fixed' => false,
             'unsigned' => false,
             'notnull' => true,
             'default' => '\'enduser\'::character varying',
             'primary' => false,
             ));

So, the default value is showing some PostgreSQL meta information. We fixed this by changing function listTableColumns():

            if (preg_match("/^nextval\('(.*)'(::.*)?\)$/", $description['default'], $matches)) {

                $description['sequence'] = $this->conn->formatter->fixSequenceName($matches[1]);
                $description['default'] = null;
            }
+           elseif (preg_match("/^'(.*)'::character varying$/", $description['default'], $matches)) {
+               $description['default'] = $matches[1];
+           }

            $columns[$val['field']] = $description;





[DC-73] TestCase framework normally uses identityMap for records created in prepareData() what can cause side effects Created: 30/Sep/09  Updated: 30/Oct/09  Resolved: 30/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.1.4
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Critical
Reporter: Jacek Dębowczyk Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File DC73-full.patch     File DC73TestCase.php    

 Description   

All new records are stored in the identityMap during insertion. This default behavior takes place also while executing test cases.

In other words every record created in the prepareData() method gets to the identityMap. Afterwards, in a test method, it is silently retrived from identityMap instead of (expected!) quering from sqlite.

IMHO a testing environment should be as pure as possible and no such side effects are acceptable.

I'm including a test case and patch for Doctrine_UnitTestCase. After putting the patch, I have found that 2 test cases causes fail: 1449 and 736. In the first test IMHO there is a problem in a content test - I'm including appropriate fix.
It seems that the second test, in fact, have never been passing. I think that positive result was caused by the side effect of identityMap.



 Comments   
Comment by Jonathan H. Wage [ 13/Oct/09 ]

This breaks the 1.2 test suite. Can you retry your patch?

Comment by Jacek Dębowczyk [ 20/Oct/09 ]

Yes, the patch breaks 2 test cases: 1449 and 736.
I explained it above in the ticket description.

Comment by Jonathan H. Wage [ 20/Oct/09 ]

Does your patch fix those 2 failing test cases now?

Comment by Jacek Dębowczyk [ 20/Oct/09 ]

Ok, now I'm including a patch that also fixes both test cases and causes all 1.2 tests passes.





[DC-573] Invalid SQL generated by Doctrine_Query::getLimitSubquery() when ordering by multiple columns Created: 15/Mar/10  Updated: 15/Mar/10  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Critical
Reporter: Craig Marvelley Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PHP 5.3
Windows XP
MSSQL Server 2008


Attachments: Text File doctrine_query_patch.patch     File index.php     File Query.php    

 Description   

When attempting to order a query by multiple columns I came across this bug. I've attached a reproduction script which will hopefully illustrate the behaviour, but essentially getLimitSubquery() is parsing the order by column incorrectly, leading to an erroneous comma in the sub-select field select clause, e.g

SELECT [m].[id] AS [m__id], [m].[name] AS [m__name], [m].[date] AS [m__date], [r].[id] AS [r__id], [r].[model_id] AS [r__model_id], [r].[name] AS [r__name] FROM [model] [m] INNER JOIN [relation] [r] ON [m].[id] = [r].[model_id] WHERE [m].[id] IN (SELECT TOP 1 [inner_tbl].[id] FROM (SELECT DISTINCT TOP 1 [m].[id], [r].[name],, [r].[id] FROM [model] [m] INNER JOIN [relation] [r] ON [m].[id] = [r].[model_id] ORDER BY [r].[name], [r].[id]) AS [inner_tbl] ORDER BY [inner_tbl].[name] DESC, [inner_tbl].[id] DESC) ORDER BY [r].[name], [r].[id]

(note [r].[name],, [r].[id] - that's the offender).

I've attached a patch against 1.2 HEAD that strips any commas from the fields before they are added to the select clause; it works for me but I'm not sure of all the use cases across the relevant drivers.



 Comments   
Comment by Jonathan H. Wage [ 15/Mar/10 ]

I don't see any patch attached to the ticket. If you can provide more information and a diff/patch we can consider it for the next release. Thanks, Jon

Comment by Craig Marvelley [ 15/Mar/10 ]

Sigh. Sorry, attached the file instead of the patch.

Comment by Jonathan H. Wage [ 15/Mar/10 ]

Thanks for the issue and patch





[DC-565] Versionable bugging when used with I18N Created: 12/Mar/10  Updated: 15/Mar/10  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: None
Fix Version/s: 1.2.2

Type: Bug Priority: Critical
Reporter: Sid GBF Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: File audit_log.diff    

 Description   

The solution was to allow Versionable to skip fields.
I've fixed with this changing:

Doctrine/AuditLog.php
#84:

$skipFields = (isset($this->_options['skipFields']))?$this->_options['skipFields']:array();

#88:

//inside the foreach
if(in_array($column, $skipFields))

Unknown macro: { continue; }

After that the Versionable will accept some parameters.

ps: If possible, let me know about this changes cause my sources are with this fix.






[DC-524] Out Of Range in Template Geographical Calculation using Postgresql Created: 25/Feb/10  Updated: 01/Mar/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Geographical
Affects Version/s: 1.2.0
Fix Version/s: 1.2.2

Type: Bug Priority: Critical
Reporter: Nei Rauni Santos Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PostgreSQL 8.3 on Linux


Attachments: Text File Geographical.patch    

 Description   

500 | Internal Server Error | Doctrine_Connection_Pgsql_Exception
SQLSTATE[22003]: Numeric value out of range: 7 ERROR: input is out of range

DQL:

at Doctrine_Connection->execute('SELECT h.id AS h_id, h.name AS hname, h.address AS haddress, h.zip AS hzip, h.url AS hurl, h.photo_url AS hphoto_url, h.checkin_from AS hcheckin_from, h.checkin_to AS hcheckin_to, h.checkout_from AS hcheckout_from, h.checkout_to AS hcheckout_to, h.is_published AS his_published, h.class AS hclass, h.currencycode AS hcurrencycode, h.minrate AS hminrate, h.maxrate AS hmaxrate, h.preferred AS hpreferred, h.nr_rooms AS hnr_rooms, h.bookable_direct AS hbookable_direct, h.ranking AS hranking, h.city_id AS hcity_id, h.policygroup_id AS hpolicygroup_id, h.is_closed AS his_closed, h.hoteltype_id AS hhoteltype_id, h.class_is_estimated AS hclass_is_estimated, h.review_nr AS hreview_nr, h.review_score AS hreview_score, h.created_at AS hcreated_at, h.updated_at AS hupdated_at, h.latitude AS hlatitude, h.longitude AS hlongitude, ((ACOS(SIN(45.41244780000000000000 * PI() / 180) * SIN(h.latitude * PI() / 180) + COS(45.41244780000000000000 * PI() / 180) * COS(h.latitude * PI() / 180) * COS((6.63685100000000000000 - h.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS h0, ((ACOS(SIN(45.41244780000000000000 * PI() / 180) * SIN(h.latitude * PI() / 180) + COS(45.41244780000000000000 * PI() / 180) * COS(h.latitude * PI() / 180) * COS((6.63685100000000000000 - h.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515 * 1.609344) AS h1 FROM hotel h WHERE (((ACOS(SIN(45.41244780000000000000 * PI() / 180) * SIN(h.latitude * PI() / 180) + COS(45.41244780000000000000 * PI() / 180) * COS(h.latitude * PI() / 180) * COS((6.63685100000000000000 - h.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515 * 1.609344) < 3 AND h.is_published = ? AND h.id != ?) ORDER BY h_1 asc LIMIT 5', array('true', 189646))

in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query/Abstract.php line 976

I'm using NUMERIC on column type with precision 10, but the problem is not in the column latitude and longitude, it´s on calculation.
To resolve this bug I made a casting inside of ACOS function calculation, but I don't know how it work on mysql.

      • I've posted a patch file attached here with the change that I made.

Examples of result of h_0, h_1 on sql fixed.

0.132901717706014221300; 0.213884392376139928479590400
0.15938002241913817800; 0.256497124695862251207283200
0.205676327970298764600; 0.331003964361032495016422400
0.205676327970298764600; 0.331003964361032495016422400






[DC-521] Empty records cannot be inserted on PostgreSQL with autoincrement identifiers Created: 23/Feb/10  Updated: 17/Jun/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Critical
Reporter: Gergely Kis Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Ubuntu 9.10
PostgreSQL 8.4
PHP 5.2.10-2ubuntu6.4
Doctrine 1.2 stable branch (r7206)


Attachments: Text File doctrine-1.2-emptyinsert.patch    

 Description   

If a record does not have any values set, but its identifier is defined as autoincrement, the record cannot be inserted into PostgreSQL.

In Doctrine_Connection_UnitOfWork::processSingleInsert():

 
       $fields = $record->getPrepared();
        $table = $record->getTable();

       // Populate fields with a blank array so that a blank records can be inserted
        if (empty($fields)) {
            foreach ($table->getFieldNames() as $field) {
                $fields[$field] = null;
            }
        }

This code snippet will add null values to all fields, including to the autoincrement identifier.
Then later in Doctrine_Connection_Pgsql::insert():

       // fix #1786 and #2327 (default values when table is just 'id' as PK)
        if(count($fields) === 1 && $table->isIdentifier(key($fields)) && $table->isIdentifierAutoincrement() )
        {
            return $this->exec('INSERT INTO ' . $this->quoteIdentifier($tableName)
                              . ' '
                              . ' VALUES (DEFAULT)');
        }

        foreach ($fields as $fieldName => $value) {
            $cols[] = $this->quoteIdentifier($table->getColumnName($fieldName));
            if ($value instanceof Doctrine_Expression) {
                $a[] = $value->getSql();
                unset($fields[$fieldName]);
            } else {
                $a[] = '?';
            }
        }

The claimed fix for the referenced tickets does not work correctly for 2 reasons:
1. It only works for tables with a single id field
2. It only works correctly if the id field had no value assigned. If there was a value assigned, it silently bypasses it, and inserts with the autoincremented value.

Patch with test case will be attached to the ticket.

References:
http://trac.doctrine-project.org/ticket/2327
http://trac.doctrine-project.org/ticket/1786



 Comments   
Comment by Gergely Kis [ 23/Feb/10 ]

The patch contains:

  • Fix for the empty insert issue in PostgreSQL
  • Fix in the UnitOfWork to handle autoincrement fields correctly, if an increment field value was explicitly specified (previously it queried the lastInsertId(), which fails for postgres, since it uses a sequence, which is not updated in case an id is explicitly inserted. (It might be a good idea to also move the postgres sequence in the Pgsql::insert() to the maximum inserted value to make sure that it correctly simulates autoincrement fields, and does not generate conflicting ids -> this is not done yet)
  • Add unit test
  • Add tearDown() support for the unit test framework
  • Fix 741 ticket test (it seems to have relied on a bug in the handling of autoincrement fields: basically a second record was inserted silently) The correct state is DIRTY instead of TDIRTY.
  • Put the new unit test onto the exclusion list because it interferes with the Query test (despite using tearDown() to reset the connection). It also relies explicitly on PostgreSQL.
Comment by Gergely Kis [ 25/Feb/10 ]

Increasing priority to critical because this is a major issue with the current 1.2 series.

Comment by Enrico Stahn [ 17/Jun/10 ]

Environment: doctrine 1.2.4, symfony 1.4

I moved our project from doctrine 1.2.1 to 1.2.4. The build process stops because of this patch. We are using primary keys with an alias. It seems that the generation of the sequence name in the build-process is different to the one used in UnitOfWorks.

Example:

Authority:
columns:
a_id:

{ name: a_id as id, type: integer, primary: true, autoincrement: true }

name:

{ type: string }

This will generate a sequence called "authority_a_id", but it will try no "currval" the sequence "authority_id".

I'll try to provide a UnitTest. The current seems broken.

php -l Ticket/DC521TestCase.php
PHP Parse error: syntax error, unexpected $end, expecting T_FUNCTION in Ticket/DC521TestCase.php on line 143

Parse error: syntax error, unexpected $end, expecting T_FUNCTION in Ticket/DC521TestCase.php on line 143
Errors parsing Ticket/DC521TestCase.php

Comment by Enrico Stahn [ 17/Jun/10 ]

@see DC-747





[DC-460] Doctrine_Cache_Apc/Core changes in 1.2 cause instability and crashes Created: 27/Jan/10  Updated: 01/Mar/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Caching
Affects Version/s: 1.2.0, 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Critical
Reporter: David Abdemoulaie Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
Reference
relates to DC-390 doctrine_cache_keys bigger than 1mb Open

 Description   

Since upgrading to Doctrine 1.2 my application has begun to get increasingly slower as hours elapse. I've pinpointed the cause to the new doctrine_cache_keys feature.

I've found at least three issues with this new method.

First

The key cache does not track enforce unique entries, thus multiple entries can be in the cache. See:

    protected function _saveKey($key)
    {
        $keys = $this->fetch($this->_cacheKeyIndexKey);
        $keys[] = $key;

        return $this->save($this->_cacheKeyIndexKey, $keys, null, false);
    }

    public function _deleteKey($key)
    {
        $keys = $this->fetch($this->_cacheKeyIndexKey);
        $key = array_search($key, $keys);
        if ($key !== false) {
            unset($keys[$key]);

            return $this->save($this->_cacheKeyIndexKey, $keys, null, false);
        }

        return false;
    }

Second

The doctrine_cache_key is being updated on every cache save or delete. With any caching strategy (APC, Memcached, Xcache) cache writes for the same key are (naturally) serialized. This leads to the "timebomb" situation described here: http://t3.dotgnu.info/blog/php/user-cache-timebomb.html

The problem is exarcerbated by the infinitely increasing size of the doctrine_cache_key array noted above. Depending on the caching engine, the lock time increases as well (APC & XCache free the previous entry inside the lock). This causes the application to spiral out of control, even with relatively trivial loads.

Personally, I don't think the "benefit" of having prefix/regex deletes is worth having this. Jon, you suggested having it disabled by default, but even with it enabled, this problem is reintroduced when someone decides to use it.

Third

For most (maybe all?) cache engines the doctrine_cache_key seems entirely unnecessary.

  1. APC
    • apc_cache_info('user') returns the list of cache entries
  2. Memcached
    • $memcache->getExtendedStats('cachedump', $slabId) can return the list of cache keys
  3. XCache
    • According to the API docs xcache_list() behaves similar to apc_cache_info()
  4. DB
    • a simple query can get this
  5. Array
    • array_keys() ?

Summary

As this is currently broken for production use I intend to immediately fix both the first and second items above by preventing duplicate entries and disabling the doctrine_cache_keys behavior by default.

With more input/discussion I think the long term solution is to use the tools provided by the engines to get a list of keys, rather than maintain a list. I'd be willing to develop this as long as it is approved.



 Comments   
Comment by David Abdemoulaie [ 27/Jan/10 ]

I fixed the first issue in the following revision:

http://trac.doctrine-project.org/changeset/7070

cache_keys entries are now stored as the key of an array. This allows for simple uniqueness enforcement, as well as being significantly faster for deletion: array_key_exists is O(log n), array_search is O( n ).

Comment by Roman S. Borschel [ 27/Jan/10 ]

I have to agree with this feature turning out to be extremely problematic. See DC-390 for a related problem (I linked it to this one). It should really be disabled by default, at least. Of course it can not be stripped out of 1.2.

We will strongly reconsider it in 2.0.

Comment by David Abdemoulaie [ 27/Jan/10 ]

Jon,

I was about to backport the 2.0 code to allow enabling/disabling the use of doctrine_cache_keys, but I noticed that it is already in 1.2 at the last second:

    public function save($id, $data, $lifeTime = false, $saveKey = true)

I think the 2.0 method is the better way to go about doing this, because afaik users generally don't call save() directly, the Doctrine code does. Thus there's really no way to disable this class-wide.

I don't know if such an API change is acceptable to you in 1.2 though. I think it should be done due to the basic unusability of 1.2 caching in production.

If not, can we just change the $saveKey param default to false?

Comment by David Abdemoulaie [ 29/Jan/10 ]

Per discussion on IRC I have completely removed the doctrine_cache_keys functionality from Doctrine_Cache.

The deleteByPrefix(), deleteBySuffix(), and deleteByRegex() methods are still present, but they use driver-specific methods to retrieve a list of cache keys. Due to this the following methods have been deprecated and removed:

  • Doctrine_Cache_Driver::count() — Counting is no longer possible or relevant because the items cached by Doctrine are indistinguishable from items cached from other parts of your application(s)
  • Doctrine_Cache_Driver::deleteAll() — Same as above.

The only other API change made is the signature of the Doctrine_Cache_Interface::save() methods:

    public function save($id, $data, $lifeTime = false, $saveKey = true)

is now

    public function save($id, $data, $lifeTime = false)

See r7074 and r7075

Comment by David Abdemoulaie [ 29/Jan/10 ]

Ported changes to 2.0 trunk in r7076





[DC-240] Automatic ordering through orderBy in many-to-many relation definition issue Created: 17/Nov/09  Updated: 17/Nov/09  Resolved: 17/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Record, Relations
Affects Version/s: 1.2.0-BETA3
Fix Version/s: 1.2.0-RC1

Type: Bug Priority: Critical
Reporter: Maciej Hołyszko Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 1
Labels: None
Environment:

1.2 svn



 Description   

I would like to utilize new nice feature in Doctrine 1.2, namely automatic ordering of relations using orderBy property in relation definition. However I see small flaw with m2m relations:

class User extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->setTableName('core_users');
		
		$this->hasColumn('username', 'string', 64, array('notnull' => true));
		$this->hasColumn('password', 'string', 128, array('notnull' => true));
	}
	
	public function setUp()
	{
		$this->hasMany('Role as Roles', array('local' => 'id_user', 'foreign' => 'id_role', 'refClass' => 'UserRole', 'orderBy' => 'position'));
		$this->actAs('SoftDelete');
	}
}

class Role extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->setTableName('core_roles');
		
		$this->hasColumn('name', 'string', 64);
	}
	
	public function setUp()
	{
		$this->hasMany('User as Users', array('local' => 'id_role', 'foreign' => 'id_user', 'refClass' => 'UserRole'));
		$this->hasMany('Role as Parents', array('local' => 'id_role_child', 'foreign' => 'id_role_parent', 'refClass' => 'RoleReference', 'orderBy' => 'position'));
		$this->hasMany('Role as Children', array('local' => 'id_role_parent', 'foreign' => 'id_role_child', 'refClass' => 'RoleReference'));
	}
}

class UserRole extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->setTableName('core_users_roles');
		
		$this->hasColumn('id_user', 'integer', null, array('primary' => true));
		$this->hasColumn('id_role', 'integer', null, array('primary' => true));
		$this->hasColumn('position', 'integer', null, array('notnull' => true));
	}
	
	public function setUp()
	{
		$this->hasOne('User', array('local' => 'id_user', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
		$this->hasOne('Role', array('local' => 'id_role', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
	}
}

class RoleReference extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->setTableName('core_roles_reference');
		
		$this->hasColumn('id_role_parent', 'integer', null, array('primary' => true));
		$this->hasColumn('id_role_child', 'integer', null, array('primary' => true));
		$this->hasColumn('position', 'integer', null, array('notnull' => true));
	}
	
	public function setUp()
	{
		$this->hasOne('Role as Parent', array('local' => 'id_role_parent', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
		$this->hasOne('Role as Child', array('local' => 'id_role_child', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
	}
}

$query = Doctrine_Query::create()
	->from('User u')
	->leftJoin('u.Roles r')
	->orderBy('username ASC')
	->execute();

Results in following query being generated:

SELECT `c`.`id` AS `c__id`, `c`.`username` AS `c__username`, `c`.`password` AS `c__password`, `c`.`deleted_at` AS `c__deleted_at`, `c2`.`id` AS `c2__id`, `c2`.`name` AS `c2__name` FROM `core_users` `c` LEFT JOIN `core_users_roles` `c3` ON (`c`.`id` = `c3`.`id_user`) LEFT JOIN `core_roles` `c2` ON `c2`.`id` = `c3`.`id_role` WHERE (`c`.`deleted_at` IS NULL) ORDER BY `c`.`username` ASC, position

As you can see, 'position' column at the end is not prefixed by an alias (should be `c3` here), which may arise problems when there are more than one column of that name used within tables used in the query.

Same with lazy-loading:

$query = Doctrine_Query::create()
	->from('User u')
	->orderBy('username ASC');
	
$result = $query->execute();
foreach($result as $item)
{
	echo count($item->Roles);
}

SELECT `c`.`id` AS `c__id`, `c`.`name` AS `c__name`, `c2`.`id_user` AS `c2__id_user`, `c2`.`id_role` AS `c2__id_role`, `c2`.`position` AS `c2__position` FROM `core_roles` `c` LEFT JOIN `core_users_roles` `c2` ON `c`.`id` = `c2`.`id_role` WHERE (`c2`.`id_user` IN (?)) ORDER BY position





[DC-238] Doctrine_Query::count() doesn't follow useResultCache Created: 16/Nov/09  Updated: 17/Nov/09  Resolved: 17/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.1.5
Fix Version/s: 1.2.0-RC1

Type: Improvement Priority: Critical
Reporter: Fabian Spillner Assignee: Guilherme Blanco
Resolution: Fixed Votes: 1
Labels: None

Attachments: File doctrine-query-count-cache.diff    

 Description   

The count method of Doctrine_Query doesn't follow useResultCache option, so I have to make loop away with fetchOne or something like that use "execute()".

So I fixed this issue, see the attachment for details!



 Comments   
Comment by Jonathan H. Wage [ 17/Nov/09 ]

I decided to fix this in Doctrine 1.2 before it really is too late.





[DC-236] Doctrine_Collection->toHierarchy() : __children field doesn't contain correct children Created: 16/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Nested Set
Affects Version/s: 1.2.0-BETA1, 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Critical
Reporter: Nate Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PHP 5.2.9 on Windows Server 2003 with MySQL



 Description   

This bug was discovered while using getDescendants with the new toHierarchy function. Rather than containing the correct child elements in the __children field, it contains whatever the next record is. Each record only has a single child, which is the record with the next-highest lft value. You can see this in the following pastebin. Notice that the very bottom element is placed around level 15 in the tree, yet it should be level 4 according to the "level" field.

The line that was used to produce the above pastebin was:
print_r($children = $file->getNode()>getDescendants(null, false)>toHierarchy()->toArray());
The class used for $file is: http://pastebin.ca/1673706



 Comments   
Comment by Jonathan H. Wage [ 16/Nov/09 ]

Thanks for reporting the issue, it is fixed now.





[DC-223] Cloning a query object re-creates hydrator object and loses hydration mode in the process. Created: 12/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Critical
Reporter: Reko Tiira Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File Doctrine_Query.patch    

 Description   

This is obviously wrong since cloning should result in identical object, but why this is such a critical bug is because it breaks setting array hydration for nested set base query, because the query object gets cloned during the fetching of tree. This bug was introduced in revsion 6691 in attempt to fix DC-204. Included is a patch that correctly clones the hydrator instead of resetting its information completely.






[DC-25] Joining the same m2m relation more than one time produces query with duplicated aliases Created: 15/Sep/09  Updated: 24/Sep/09  Resolved: 24/Sep/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.1.4
Fix Version/s: None

Type: Bug Priority: Critical
Reporter: Jacek Jędrzejewski Assignee: Roman S. Borschel
Resolution: Fixed Votes: 0
Labels: None


 Description   

moved my ticket #1941 from trac

Let's consider an environment:

We have a table "Article" and another table "Tag". There is a many to many relation between those two tables via link table "TagArticle". Schema and fixtures provided in attachments. It is simple.

Now let's consider a situation:

We want to display a list of all articles with on of tags. But we want to display this list also with the rest of tags connected to articles with specified tag:

Article1: tag1, tag2, tag3, tag4
Article2: tag2, tag3
Article3: tag4

We want a list of all articles with "tag2" - so it will be Article1 and Article2, but the same query should also retrieve the rest of tags.

It is really simple to do with one-to-many relation: by just joining two tables with different aliases.

However, it is impossible now to do it with many-to-many relation, because Doctrine generates wrong table aliases in SQL.

$query = Doctrine_Query::create()->select('a.id, tg.*')
    ->from('Article a')
    ->leftJoin('a.Tags tg')
    ->innerJoin('a.Tags tg2 WITH tg2.name = ?', 'tag2')
    ;

Looks logical. But it throws an exception:

"Doctrine_Connection_Mysql_Exception" with message "SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 't2'" in ...doctrine\lib\DoctrineConnection.php:1084

Let's look at our query:

SELECT a.id AS a__id, t.id AS t__id, t.name AS t__name 
FROM article a 
LEFT JOIN tag_article t2 ON a.id = t2.article_id 
LEFT JOIN tag t ON t.id = t2.tag_id 
INNER JOIN tag_article t2 ON a.id = t2.article_id 
INNER JOIN tag t3 ON t3.id = t2.tag_id AND t3.name = ?

As we can see, there is a duplicated alias on "tag_article".



 Comments   
Comment by Guilherme Blanco [ 24/Sep/09 ]

This issue was fixed in r6407





[DC-851] Temporary schema filename is not unique enough Created: 01/Sep/10  Updated: 01/Sep/10  Resolved: 01/Sep/10

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.3
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Tristan Rivoallan Assignee: Jonathan H. Wage
Resolution: Invalid Votes: 0
Labels: None

Attachments: Text File tmp_schema_unicity.patch    

 Description   

Random filename generation is not sufficiently unique when working with multiple developers on a single development server.

$file = realpath(sys_get_temp_dir()).'/doctrine_schema_'.rand(11111, 99999).'.yml';

Attached patch replaces rand() call with a uniqid() call.



 Comments   
Comment by Jonathan H. Wage [ 01/Sep/10 ]

This issue is in the Symfony code, not Doctrine. Please open a ticket in http://trac.symfony-project.org





[DC-458] Doctrine_Validator_Ip fails on IPV6 IP addresses. Created: 27/Jan/10  Updated: 01/Mar/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Validators
Affects Version/s: 1.1.6
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Josh Boyd Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File fix_ip_validator_to_validate_ipv6_and_ipv4.patch    

 Description   

Doctrine_Validator_Ip->validate() uses ip2long() in order to validate IP addresses.

However, ip2long() only works for IPv4 addresses, and not IPv6 addresses.

Attached is a patch to use filter_var which validates both IPv4 and IPv6 properly.






[DC-446] Doctrine_Record_Generator::createClass with Doctrine_Record_Listener Created: 25/Jan/10  Updated: 02/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Record
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Improvement Priority: Major
Reporter: Hans-Peter Oeri Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: File diff    

 Description   

Doctrine_Record_Generator::initialize first builds the table class and then a "Doctrine_Record" from that. This is surprising, as the result is a "double conversion" from record to table and back.

Furthermore, writing files, no record listeners can be attached (see createClassFromTable)!

I therefore suggest adding the possibility to add listeners - which the builder already does! - to the Record_Generator.






[DC-437] Connection::query() can use wrong connection Created: 19/Jan/10  Updated: 15/Mar/10  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.0, 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Eugene Janusov Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File DC-437.patch     File DC437TestCase.php    

 Description   

As I understand, Doctrine_Connection::query() method is intended to execute DQL queries using precisely this connection.
But here is the code:

894     public function query($query, array $params = array(), $hydrationMode = null)
895     {
896         $parser = Doctrine_Query::create();                                                                                
897         $res = $parser->query($query, $params, $hydrationMode);
898         $parser->free();
899 
900         return $res;
901     }

Doctrine_Query::create() statement will create a query that is using a default connection, not the current one.



 Comments   
Comment by Eugene Janusov [ 19/Jan/10 ]

Attached proposed patch.

Comment by Eugene Janusov [ 19/Jan/10 ]

Attached test case.





[DC-428] Bug on DropDB on Oracle. The sequence isn't not correct Created: 15/Jan/10  Updated: 11/Mar/10  Resolved: 11/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Bertrand Zuchuat Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File Oracle.php.patch    

 Description   

The sequence of drop database is not correct.

I change this in my patch.

Thank's



 Comments   
Comment by Miloslav "adrive" Kmet [ 31/Jan/10 ]

Hi Bertrand,

Can you provide more informations on this issue? Some test cases, oracle error messages, oracle settings..

You are proposing to remove the double quotes from DROP TABLE statements. You can turn identifier quoting on and off. When you have ATTR_QUOTE_IDENTIFIERS to on, all your identifier names are double quoted in oracle and if you do something like
SELECT * FROM user_tables, the TABLE_NAME column contains table names lovercased. So you need the double quotes in DROP TABLE statements. If your table name is "my_table" and you do DROP TABLE my_table; you get an error about nonexistent table. You need to do DROP TABLE "my_table". That's exactly what doctrine does now.

Another scenario is doublequotes turned off. So all your tables are handled in oracle uppercased. So my_table is internally handled as MY_TABLE. That's alredy what you recieve from USER_TABLES. And when you do DROP TABLE "MY_TABLE" that is the same as DROP TABLE my_table.

I use this heavily in both cases and I have no problems with that.

The issue with I.SEQUENCE_OWNER in DROP SEQUENCE statement I fixed in r6896 (http://trac.doctrine-project.org/changeset/6896).

Comment by Bertrand Zuchuat [ 31/Jan/10 ]

Hi,

The symfony use the last version 1.2.1 revision 6894 and the change is on 6896.

A release date for version 1.2.2 ?

Thank's for your help.

Comment by Miloslav "adrive" Kmet [ 31/Jan/10 ]

Just update it yourself with svn up or use your version in YOUR_PROJECT/lib/vendor/doctrine.





[DC-419] Sluggable and inheritance Created: 11/Jan/10  Updated: 06/Sep/11  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Behaviors
Affects Version/s: 1.2.0
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Pierre B Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 2
Labels: None
Environment:

Symfony 1.4.1 LAMP


Attachments: Text File sluggable.patch    

 Description   

I've the same problem than this post : http://groups.google.com/group/doctrine-user/browse_thread/thread/3737fd293fef5fda/d86a8bc2578e4bac

Then, I've set "uniqueBy: [name, type] ", and my data goes in database BUT they can have the same slug.

So I can't retrieve an objects wich has equal slug with another.

The column aggregation inheritance does'nt take care of others slugs.



 Comments   
Comment by Jan Míšek [ 01/Mar/10 ]

First, inheritance is great feature, thanks doctrine team.

But I have this problem too.

I have identified, the problem is related to class: "Doctrine_Template_Listener_Sluggable", to method: getUniqueSlug($record, $slugFromFields). In mentioned method, table is retrieved from $record ($record->getTable()), but record could be inherited class, so query result on the table is limited only to records of the inherited class. But there could be already rows of other inherited classes with same slug in the database.

Fast hack to solve it, works for me:

  • Added option variable to behaviour "table"
  • Replaced all calls $record->getTable() as Doctrine::getTable($this->_options['table'])
Comment by Ivar Nesje [ 02/Mar/10 ]

Thanks for the solution. I do not like the idea of patching the core framework, but it's just how we will have to deal with it. I hope someone will comment on this bugreport so that I'll be informed when the issue is fixed.

The point of sluggable with column aggregation inheritance is to have a unique identifier to make a common interface for all entitis. Like /events/:slug where the presentation is dependent on the modell.
Ofcourse I could have set up one route for every child class, but that will make more code for configuration, whitch is a pain to maintain.

Comment by Jonathan H. Wage [ 02/Mar/10 ]

Can anyone provide a patch for the change so I can see everything clearly? Thanks, Jon

Comment by Ivar Nesje [ 03/Mar/10 ]

Here is a simple patch implementing the changes Jan Míšek proposed. (as far as I understod them)

To make the solution better, it would be nice if the Behaviour somhow found out that it was a child class (without requirering me to specify the parent ) and made sure that it made a slug unique across all subclases, unless the unique by setting spesified the type column. I'm realy glad I had a lot of data to import from a previous site, so that I discovered this bug. I use column aggregation inheritance to make the code for presenting different events in a different way simple. But every event sholud be accessable trough the same route mysite.com/events/:slug.

Comment by Ivar Nesje [ 03/Mar/10 ]

I hope this patch and test cases solves more than my problems.

Comment by Ivar Nesje [ 04/Mar/10 ]

Updated the patch a little, so that it does not try to instanciate an abstract class as doctrine generates them.

I was walking up the inheritance tree and tried to instanciate the class right under DoctrineRecord unfortunatly in symfony there is many layers of abstract classes before you find the base class. Now the plugin walks back to the highes not abstract class

Comment by Jonathan H. Wage [ 15/Mar/10 ]

Thanks for the issue and patch.

Comment by Klemens Ullmann-Marx [ 09/Apr/10 ]

This fix breaks my system.

@see: http://groups.google.com/group/doctrine-dev/browse_thread/thread/8028e51d5bde27eb

Comment by Ivar Nesje [ 09/Apr/10 ]

Hmm.. I'm sory that my ugly fix to remove the 'where type = $type' part of the query to find existing slugs that might cause a colission with the proposed slug.

Does anyone have a better idea on how to ask for all slugs in the same model? I had a pretty hard time traversing the inheritance tree to find the right parent class that were not abstract. I see that something similar has been done about soft delete, so that a new record would not get the same slug as a record marked as deleted, but not removed from the databse.

Comment by Klemens Ullmann-Marx [ 06/Sep/11 ]

Here's an improved patch with a better algorithm to find the column aggregation inhertiance base class:

http://trac.ullright.org/browser/trunk/plugins/ullCorePlugin/patch/Sluggable.patch?rev=3067

This fixes my problem (see above)





[DC-411] Doctrine::Inflector does not handle table names with dashes Created: 08/Jan/10  Updated: 01/Mar/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.2
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Tomasz Sterna Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

I have some tables in my DB with dashes in name, ex. "table-name".
While generating schema.yml with ./doctrine-cli generate-yaml-db it generated model classes with dashes, ex. class Table-name ...

Here's a small patch to treat - in table names same as _.

— library/Doctrine/Inflector.php (wersja 7016)
+++ library/Doctrine/Inflector.php (kopia robocza)
@@ -57,7 +57,7 @@
public static function classify($word)

{ $word = preg_replace('/[$]/', '', $word); - return preg_replace_callback('~(_?)(_)([\w])~', array("Doctrine_Inflector", "classifyCallback"), ucfirst(strtolower($word))); + return preg_replace_callback('~(_?)([-_])([\w])~', array("Doctrine_Inflector", "classifyCallback"), ucfirst(strtolower($word))); }

/**



 Comments   
Comment by Tomasz Sterna [ 08/Jan/10 ]

linebreaks got lost.
basically (_)([\w]) turns to ([-_])([\w])





[DC-404] Allow custom language field name in I18n Behavior Created: 07/Jan/10  Updated: 01/Mar/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Behaviors, I18n
Affects Version/s: 1.2.1, 1.2.2
Fix Version/s: 1.2.2

Type: New Feature Priority: Major
Reporter: Steve Lounsbury Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: File i18n_configurable_field.diff    

 Description   

I18n behavior assumes language field name of 'lang'. It would be nice if this was configurable.

This was mentioned and a proposed solution was given here: http://forum.symfony-project.org/index.php/m/85623/

I've attached a patch which implements this solution, it essentially adds an i18nField option to the behaviour. The field defaults to 'lang'.

The patch was made against r7016 of the 1.2 branch.

Note:

  • Leaving the field name as 'lang' does not cause unit test failures.
  • Changing the name of the field does cause some unit tests to fail for me. I'm not sure if the dependency on the field name exists in the unit tests or in the doctrine library itself. If dependencies exist in the library, this patch may not be sufficient to add the feature.

Sorry if the patch is incomplete, I'm new to Doctrine in general.






[DC-398] PORTABILITY_EMPTY_TO_NULL doesn't do anything for statements Created: 05/Jan/10  Updated: 15/Mar/10  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.0.14, 1.1.6, 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Thomas Albright Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 1
Labels: None

Attachments: File patch.diff    

 Description   

I found this ticket on the old Trac system, but not on JIRA. It is still broken in the 1.1 branch, as of revision 7004. It is also broken in 1.0.14, 1.1.6, and 1.2.1. (These were the 'stable' releases at the time I reported this bug.) It is likely broken in older releases as well.

When saving to the database, Doctrine ignores the setting of PORTABILITY_EMPTY_TO_NULL. Currently, it will never change empty strings to NULL, no matter what the setting is for ATRR_PORTABILITY. This is because there is an error in the following 'if' statement:

Doctrine_Connection_Statement starting on line: 234

if ($this->_conn->getAttribute(Doctrine::PORTABILITY_EMPTY_TO_NULL)) {
    foreach ($params as $key => $value) {
        if ($value == '') {
            $params[$key] = null;
        }
    }
}

the first test in this block should be (Portability Mode Attributes must be handled this way):

if ($this->_conn->getAttribute(Doctrine::ATTR_PORTABILITY) & Doctrine::PORTABILITY_EMPTY_TO_NULL) {

the second test should be:

if (is_string($value) && $value === '')

In newer versions of php(not sure which), test for empty string must look like '===' not only '=='. It prevents integer and boolean value 0 to be handled as an empty string.



 Comments   
Comment by Dorian [ 08/Jan/10 ]

It's the same problem with.

$oDCon->setAttribute(Doctrine::ATTR_PORTABILITY, Doctrine::PORTABILITY_RTRIM);

I think Doctrine::ATTR_ don't work.

Comment by Erin Millard [ 12/Jan/10 ]

It would be really great to see this issue fixed. As for the suggested changes above, I believe the === operator checks against type also, and therefore the is_string() call is redundant.

Comment by Thomas Albright [ 22/Feb/10 ]

Here is a patch for 1.2.1.





[DC-397] unlinking of associations with aliased local-/foreignKeys is broken Created: 05/Jan/10  Updated: 02/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Florian Klucke Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: File patch_DC-397.diff    

 Description   

Doctrine_Connection_UnitOfWork->saveAssociations() does not use column-aliases for database-columns but only field-names. The following patch deals with this problem:

Index: lib/Doctrine/Connection/UnitOfWork.php
===================================================================
— lib/Doctrine/Connection/UnitOfWork.php (revision 7004)
+++ lib/Doctrine/Connection/UnitOfWork.php (working copy)
@@ -439,8 +439,8 @@
$assocTable = $rel->getAssociationTable();
foreach ($v->getDeleteDiff() as $r)

{ $query = 'DELETE FROM ' . $assocTable->getTableName() - . ' WHERE ' . $rel->getForeign() . ' = ?' - . ' AND ' . $rel->getLocal() . ' = ?'; + . ' WHERE ' . $rel->getForeignRefColumnName() . ' = ?' + . ' AND ' . $rel->getLocalRefColumnName() . ' = ?'; $this->conn->execute($query, array($r->getIncremented(), $record->getIncremented())); }




[DC-394] Searchable behavior's batchUpdateIndex fails if a table has a composite primary key. Created: 04/Jan/10  Updated: 02/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Behaviors, Searchable
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Reko Tiira Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File Doctrine_Search.patch    

 Description   

You will get the following error when you try to batchUpdateIndex a table with composite key:

Fatal error: Uncaught exception 'ErrorException' with message 'strpos() expects parameter 1 to be string, array given' in library/Doctrine/Connection.php:725

Here's the full stack trace:

Stack trace:
#0 [internal function]: Bootstrap->errorHandler(2, 'strpos() expect...', '/Users/reko/Sit...', 725, Array)
#1 /Users/reko/Sites/MyProject/library/Doctrine/Connection.php(725): strpos(Array, '.')
#2 /Users/reko/Sites/MyProject/library/Doctrine/Search.php(246): Doctrine_Connection->quoteIdentifier(Array)
#3 /Users/reko/Sites/MyProject/library/Doctrine/Template/Searchable.php(69): Doctrine_Search->batchUpdateIndex(NULL, NULL, NULL)
#4 /Users/reko/Sites/MyProject/library/Doctrine/Template/Searchable.php(81): Doctrine_Template_Searchable->batchUpdateIndex(NULL, NULL, NULL)
#5 [internal function]: Doctrine_Template_Searchable->batchUpdateIndexTableProxy()
#6 /Users/reko/Sites/MyProject/library/Doctrine/Record.php(2622): call_user_func_array(Array, Array)
#7 [internal function]: Doctrine_Record->__call('batchUpdateInde...', Array)
#8 [internal function]: In in /Users/reko/Sites/MyProject/library/Doctrine/Connection.php on line 725

I know that it's recommended that you don't use composite primary keys, but this happens to occur when you stack the I18n and Searchable behaviour together, since the Translation table I18n behavior creates uses a composite key on (id, lang).

Anyways, the bug was quite simple one to fix and I've attached a patch that fixes the issue.






[DC-385] Behavior geographical generates latitude FLOAT(18, 2), longitude FLOAT(18, 2) - it's not exact Created: 24/Dec/09  Updated: 11/Aug/11  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Behaviors
Affects Version/s: None
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Dominik.Roser Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 2
Labels: None
Environment:

symfony 1.4.1 / mysql



 Description   

The problem was already described by another person at http://trac.symfony-project.org/ticket/7763
the generated field-type is wrong, so the stored lat/long values have lost precision.



 Comments   
Comment by Hash [ 03/Mar/10 ]

This change doesn't fix the problem. The problem here is that float and double types default to (18,2) for no good reason. See line 233: http://trac.doctrine-project.org/browser/branches/1.2/lib/Doctrine/DataDict/Mysql.php?rev=7253

I think u need to let the default mysql float and double types be set if options are not specified explicitly for length/scale. This problem causes all doubles and floats to have poor 2 decimal precision.

Comment by Jonathan H. Wage [ 04/Mar/10 ]

Doctrine always sets the default if nothing is specified currently so we can't change that we can set our own length and scale though. However, I don't know what proper values would be. I'll do some tests and report back, let me know if you have any additional information. Thanks, Jon

Comment by Hash [ 23/Apr/10 ]

Well it seems that Doctrine sets the default to 18,2 but afaik that is not necessary. I would suggest that if no scale is specified then the data type is simply defined as FLOAT or DOUBLE with no scale. This works fine for Mysql in my project.

Comment by Severin Puschkarski [ 13/Oct/10 ]

On Symfony 1.4.8 / Mysql it is still not working
Setting to
type: float(18), scale: 6
enhances precission, but the numbers are rounded weirdly in the database:
for example 76.86 is stored as 76.860001
I really would appreciate a true mysql float!!!

Comment by Malcolm Hall [ 11/Aug/11 ]

Still broken on 1.2.4 the last release of 1.2 unfortunately. This is the fix I used:

Change line 239 of lib/Doctrine/DataDict/Mysql.php from:

return 'DOUBLE('.$length.', '.$scale.')';

to

return 'DOUBLE';

This gets rid of scale completely but I think its better than all doubles that don't have a defined scale limited to decimal places, which is just awful for anyone using the Geographical behaviour.





[DC-384] Nested set API allows inconsistent trees to be created Created: 23/Dec/09  Updated: 15/Mar/10  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Nested Set
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Tom Boutell Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 3
Labels: None
Environment:

Symfony 1.4


Attachments: File nest.tgz     Text File no-move-into-descendant.patch    

 Description   

First create a tree as follows:

A
B
C
D

That is, C and D are both children of B, and B is a child of A.

At this point our db looks as follows:

mysql> select SLUG, LFT, RGT, LEVEL from pk_context_cms_page;
-----------------------+

SLUG LFT RGT LEVEL

-----------------------+

/ 1 12 0
/about 10 11 1
global NULL NULL NULL
/a 2 9 1
/a/b 3 8 2
/a/b/c 4 5 3
/a/b/c/d 6 7 3

-----------------------+
7 rows in set (0.00 sec)

Now, call D->moveAsLastChildOf(C). D is now a child of C.

So far so good:

mysql> select SLUG, LFT, RGT, LEVEL from pk_context_cms_page;
-----------------------+

SLUG LFT RGT LEVEL

-----------------------+

/ 1 12 0
/about 10 11 1
global NULL NULL NULL
/a 2 9 1
/a/b 3 8 2
/a/b/c 4 7 3
/a/b/c/d 5 6 4

-----------------------+
7 rows in set (0.00 sec)

Now, call C->moveAsLastChildOf(D). This should pull D out from under C.

Instead the values of LFT and RGT get messed up:

mysql> select SLUG, LFT, RGT, LEVEL from pk_context_cms_page
-> ;
-----------------------+

SLUG LFT RGT LEVEL

-----------------------+

/ 1 12 0
/about 10 11 1
global NULL NULL NULL
/a 2 9 1
/a/b 3 8 2
/a/b/c 6 7 5
/a/b/c/d 7 6 4

-----------------------+
7 rows in set (0.00 sec)

moveAsLastChildOf should either (1) implement moving ancestors beneath their children correctly or (2) refuse to do so.

Note: these actions were carried out as separate PHP requests.

This is easy to reproduce by firing up the Apostrophe sandbox project, logging in as admin/admin, creating the page structure described, and then clicking the apostrophe in the upper left and then the Reorganize tool.

Instructions to check out the current sandbox are here:

http://www.apostrophenow.com/home/readme

You'll need to set up databases.yml and do a build --all and a data-load, that's about it.

Be sure to open a second tab so that you can have two views of the tree showing the initial state (C and D both as kids of B) so that you can drag D under C in the first tab and then try to drag C under D in the second tab. Otherwise the tree editor itself will block you from trying to move C under D.

The implementation of pkContextCMS/executeTreeMove is calling moveAsLastChildOf() in both cases and doing so to the right pages. I've added logging to verify this, look for references to TREEMOVE in the frontend_log.dev file.

We are going to add checks at the pkContextCMS level to refuse to attempt to move an ancestor beneath one of its children as a workaround, although in principle that should be possible (at least if the ancestor has no children? Not sure if it always makes sense if it does have children other than the ancestors of the new parent).



 Comments   
Comment by Dan Ordille [ 23/Dec/09 ]

I have attached a symfony project to demonstrate the problem. Project is using latest symfony version form 1.4 svn. Run test located in test/unit/corrupt.php

The test creates 3 nodes A, B, and C.
Inserts B as last child of a.
Inserts C as last child of a.
The nodes then have the following properties.

Node lft rgt lvl
A 1 6 0
B 2 3 1
C 5 5 1

A is then moved as the first child of B which causes corrupted nested sets.

Node lft rgt lvl
A 3 6 2
B 4 3 1
C 4 5 1

A is still the parent of B and C, yet its level is 2.

This problem exists whenever a node is moved into one of its children or descendants.

Comment by Dan Ordille [ 23/Dec/09 ]

I created a patch that prevents moving a node into its descendants.

I was trying to think what the ideal behavior would be in this situation, but at least this patch will prevent corruption.

Comment by Jonathan H. Wage [ 15/Mar/10 ]

Thanks for the issue Tom and patch Dan. Let me know if we still have any issues remaining.





[DC-380] Sequence SQL is not generated when exporing sql for postgres - with patch Created: 23/Dec/09  Updated: 01/Mar/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Miha Vrhovnik Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File pgsql_sql_sequence.patch    

 Description   

I spent a couple of hours on Saturday debugging why the heck the sql for sequences doesn't get generated for Postgresql. As it seems somebody forget about that when writing the export driver.

Attached is a patch against 1.2.1 version.
This probably also applies to Doctrine 2!



 Comments   
Comment by Jonathan H. Wage [ 01/Mar/10 ]

Thanks for the issue and patch.





[DC-374] importing sqlite db with doctrine does not detect autoincrement fields Created: 21/Dec/09  Updated: 01/Mar/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: aiso haikens Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

sqlite3


Attachments: Text File sqlite-autoincrement.patch    

 Description   

when importing a sqlite db with doctrine it fails to detect autoincrement fields resulting in exceptions when inserting records, like this one:
Uncaught exception 'Doctrine_Connection_Sqlite_Exception' with message 'SQLSTATE[23000]: Integrity constraint violation: 19 usergroup.group_id may not be NULL' in /Users/aiso/dev/php/cms/mix/lib/ext/doctrine/Doctrine/Connection.php:1083.

This is caused by the fact that there is no check on 'autoincrement' in Import/Sqlite.php. In sqlite3 a field is autoincrement whenever its type is integer and is a primary key.

a patch is included.






[DC-381] Automatic sequence names - with patch Created: 23/Dec/09  Updated: 01/Mar/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Improvement Priority: Major
Reporter: Miha Vrhovnik Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File schema_sequence.patch    

 Description   

Right now in yaml schema if you write sequence: true all the sequence names are set to 1.
This fixes the class generator in such way that the table name is used for sequence name if sequence === true otherwise it works just like before.






[DC-377] Cannot delete a taggable record (Taggable Extension) Created: 22/Dec/09  Updated: 10/Aug/12  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Extensions
Affects Version/s: 1.2.0, 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Fabien Pennequin Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 1
Labels: None
Environment:

PHP 5.3.1, Mac OS X (10.6), MySQL 5.0.86, Symfony 1.4.1


Attachments: Text File TaggableConstraintError.patch    

 Description   

With Taggable extension, when I try to delete a record using Taggable, I get this exception :

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`sf_sandbox/article_taggable_tag`, CONSTRAINT `article_taggable_tag_id_article_id` FOREIGN KEY (`id`) REFERENCES `article` (`id`))

If I check the sql queries generated by Doctrine, there are not "onDelete CASCADE" for one of relation added by Taggable extension.

I have write some test cases for reproduce this bug (checking if relation has a property onDelete setted to CASCADE) but I can't reproduce the thrown exception in test case because sqlite omits queries with constraint. Also, I found how to fix this bug.

The fix and test cases are available in the file attached to this ticket.



 Comments   
Comment by Jason [ 20/Apr/10 ]

Hi Jon-

Where can I find this fix?

http://svn.doctrine-project.org/extensions/Taggable/branches/1.2-1.0 (the link referenced from the docs at http://www.doctrine-project.org/extension/Taggable) doesn't have this fix.

Comment by Jason [ 20/Apr/10 ]

Sorry, it appears the patch attached above is in SVN, however this is still broken.

With Doctrine 1.2.2 sandbox configured to work with MySQL 5.x database on 5.2.10, using the following schema

{{
BlogPost:
actAs: [Taggable]
columns:
title:
type: string(255)
notnull: true
description:
type: string(255)
notnull: true
}}

the CASCADE in the constraints for the table being applied the Taggable behavior are still not being applied (see first constraint below)

{{
CREATE TABLE `blog_post_taggable_tag` (
`id` bigint(20) NOT NULL DEFAULT '0',
`tag_id` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`,`tag_id`),
KEY `blog_post_taggable_tag_tag_id_taggable_tag_id` (`tag_id`),
CONSTRAINT `blog_post_taggable_tag_id_blog_post_id` FOREIGN KEY (`id`) REFERENCES `blog_post` (`id`),
CONSTRAINT `blog_post_taggable_tag_tag_id_taggable_tag_id` FOREIGN KEY (`tag_id`) REFERENCES `taggable_tag` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
}}

Comment by Malcolm Hall [ 10/Aug/12 ]

I use Doctrine v1.2.4 and created a fix for this problem, change the _options array initialization in Taggable.php to this:

protected $_options = array(
'builderOptions' => array(),
'tagField' => null,
'cascadeDelete' => true
);

This works because parent::buildRelation() calls the buildLocalRelation() method in Generator.php which looks for the cascadeDelete and if true then it adds the necessary CASCADE params, as you can see below:

public function buildLocalRelation($alias = null)
{
...
if (isset($this->_options['cascadeDelete']) && $this->_options['cascadeDelete'] && ! $this->_options['appLevelDelete'])

{ $options['onDelete'] = 'CASCADE'; $options['onUpdate'] = 'CASCADE'; }

...

Now both parts of the taggable relation get the cascade on delete feature. So if you delete a tag OR you delete a post, the row in the taggable_tag table gets deleted too.





[DC-365] softdelete documentation is outof date Created: 17/Dec/09  Updated: 02/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Behaviors
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Gordon Franke Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

out of date http://www.doctrine-project.org/documentation/manual/1_2/en/behaviors#core-behaviors:softdelete the behavior add a deleted_at column from type timestamp






[DC-351] Moving nodes between trees doesn't work properly Created: 10/Dec/09  Updated: 01/Mar/10  Resolved: 01/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Nested Set
Affects Version/s: 1.1.6
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Przemysław Piechota Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File moveBetweenTrees.patch     File sample.yml     File schema.yml     PNG File tree_after_move without_patch.png     PNG File tree_after_move with_patch.png     PNG File tree_before.png     PNG File tree_before_update without_patch.png    

 Description   

Moving node with children from one tree too another tree is not working properly.

Database schema and fixtrues are attached to this ticket. tree_before.png.

I want move 'Children 2' with descendants to second tree as first child

code:
$treeObject = Doctrine::getTable('Tree')->findOneById(6);

$newParent = Doctrine::getTable('Tree')->findOneById(11);
$treeObject->getNode()->moveAsFirstChildOf($newParent);

This causes a problem. Doctrine inproperly moves 'Child 2' with descendants and 'GrandChild 1 of Child 3'. (picture tree_after_move without_patch.png)

I found why it's working wrong.

It is because in NestesSet.php in function _moveBetweenTrees close gap in old tree is run too fast.
After moving only node which I want, it doesn't move descendants, but it lower values lft, rgt of next old siblings of node.
And this cause that values(lft,rgt)/ranges overlap of descendants of moving node and values of old siblings with their descendants.
And during update lft/rgt/root/level for all descendants from old range of moving node, it updates also some next old siblings.

You can see this at picture tree_before_update without_patch.png, i stop script before "// Update lft/rgt/root/level for all descendants".

I've moved closing gap in old tree.

And after patching, moving node works properly. ( picture tree_after_move with_patch.png)



 Comments   
Comment by Roman S. Borschel [ 10/Dec/09 ]

I think this issue is valid and the patch correct. I remember we had that same issue in trac at some point.

+1 from me for applying that patch.

Comment by Guilherme Blanco [ 01/Mar/10 ]

In r7285 this issue was fixed. Thanks for report and patch!





[DC-342] when a table has multiple relations to an other one, then only the last one will be created in the base models Created: 08/Dec/09  Updated: 02/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Cli
Affects Version/s: 1.1.6
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Roland Huszti Assignee: Jonathan H. Wage
Resolution: Invalid Votes: 0
Labels: None
Environment:

Ubuntu Linux 9.04 64 bit, Doctrine 1.1.6 (possibly runs from a different, central server/repo), PHP 5.2.10-2ubuntu6.3 with Suhosin-Patch 0.9.7



 Description   

Amongst many tables, I have these two below. When creating the models, it only creates the "CommentsBy" relation. Even if I move those two
relations into the "Comment" table definition and I make the necessary changes, the result will be the same. However, if I put one relation
into one table and the other into the other one, then it will be created. So, that would be a work-around, but it is still just a work-around,
plus when I also want (and I want) to create realtions pointing from the Comment to the User, I run into the same issue, but now in both of the tables.

I am building a site where I want to list the comments (comment text, comment by (username), comment time) and the users, so the relations are
needed in both ways (user -> comment and comment -> user) for the different pages, and Doctrine knows the trick, but it doesn't let me do it.

I am using Smarty, so for example I could to use something like this:

$smarty->assign('theuser', Doctrine::getTable('User')->find(123456));

{$theuser.username}

{foreach $theuser.CommentsAbout item=onecomment}

{$onecomment.comment} ... {$onecomment.ByUser.username} ... {$onecomment.created}

{/foreach}

User:
tableName: user
columns:
id:
type: integer(8)
unsigned: true
notnull: false
username:
type: string(64)

... and so on ...

relations:
Comment:
alias: CommentsAbout
local: id
foreign: about_user_id
foreignType: one
type: many
Comment:
alias: CommentsBy
local: id
foreign: by_user_id
foreignType: one
type: many
actAs:
Timestampable:
created:
name: created
updated:
name: updated

Comment:
columns:
id:
type: integer(8)
primary: true
notnull: true
autoincrement: true
by_user_id:
type: integer(8)
about_user_id:
type: integer(8)
comment:
type: string
actAs:
Timestampable:
created:
name: created
updated:
name: updated



 Comments   
Comment by Mauro Chojrin [ 16/Dec/09 ]

Hi:

I hade a similar problem, and I solved it like this:

On the yml file I just changed the name of the relation to the alias I wanted to give it. i.e.:

relations:
Producer:
class: sfGuardUser
foreign: id
local: producer_id
GOSContact:
class: sfGuardUser
foreign: id
local: gos_contact_id
GOSDD:
class: sfGuardUser
foreign: id
local: gos_dd_id

Hope it helps!

Comment by Jonathan H. Wage [ 02/Mar/10 ]

If you have multiple relationships to the same model, then you need to give them aliases.





[DC-332] Doctrine_Migration_Diff doesn't work when plugin schemas are present but there is no app schema Created: 07/Dec/09  Updated: 02/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Migrations
Affects Version/s: 1.2.0
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Tom Boutell Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Symfony 1.3



 Description   

A project with plugin schemas, but no project-level schema, which Symfony is otherwise fine with:

svn co http://svn.symfony-project.com/plugins/pkContextCMSPlugin/sandbox/branches/1.3 cmstest13
cd cmstest13
./symfony doctrine:generate-migrations-diff

>> doctrine generating migration diff
>> file+ /private/var/folders/3H/3Hu3TTyjFt...TI/Tmp/doctrine_schema_81204.yml

Notice: Undefined variable: extension in /Users/boutell/Sites/cmstest13-jonwagetest/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Migration/Diff.php on line 320

Notice: Undefined variable: extension in /Users/boutell/Sites/cmstest13-jonwagetest/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Migration/Diff.php on line 324

No php or yml files found at path: "/Users/boutell/Sites/cmstest13-jonwagetest/lib/model/doctrine"



 Comments   
Comment by Jonathan H. Wage [ 02/Mar/10 ]

I fixed this at some point. It was fixed by http://trac.doctrine-project.org/changeset/7067

Please confirm or re-open if you have any issues.

Thanks, Jon





[DC-320] Doctrine_Record fails to correctly update columns named data (conflict with getData method) Created: 03/Dec/09  Updated: 12/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Record
Affects Version/s: 1.2.0
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Massimiliano Torromeo Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

linux, apache 2, mysql 5.1, php 5.2



 Description   

I have a table with a "data" column (DATE type but the issue is not strictly related to the datatype), when updating/insering a record it fails with this error:

strtotime() expects parameter 1 to be string, array given in /usr/share/pear/Doctrine/lib/Doctrine/Record.php on line 1526

With some debugging I found that the value stored in $old was the internal $data array, and not my value. I assume that there's a conflict with the get/setData methods.

Thanks.



 Comments   
Comment by Massimiliano Torromeo [ 04/Dec/09 ]

I noticed another problem related to this:
when I dump the data with "doctrine dump-data" the resulting yaml is corrupted on records with fields named "data"

Comment by Juozas Kaziukenas [ 04/Dec/09 ]

This is caused by the column having a name "data".

Because if you have Doctrine_Core::ATTR_AUTO_ACCESSOR_OVERRIDE enabled, Doctrine fill try method setField and getField and hence setData and getData breaks it.

I recommend changing a field name or disabling this option. Otherwise, this issue is Invalid (but probably need to be documented more).

Comment by Massimiliano Torromeo [ 04/Dec/09 ]

I started using Doctrine on a pre-existing database and changing all the data fields is really troublesome right now, and having AUTO_ACCESSOR_OVERRIDE would be nice.
I temporarily solved my problem by changing line 1321 of Record.php with:

if ($fieldName!="data" && $this->_table->getAttribute(Doctrine_Core::ATTR_AUTO_ACCESSOR_OVERRIDE) || $this->hasAccessor($fieldName)) {

This way I only lose the possibility of having a custom accessor for the data field and not all the others.
I still think this can be fixed, without having to disable AUTO_ACCESSOR_OVERRIDE.

If this is not a BUG maybe it could be considered a feature request then?

Comment by Juozas Kaziukenas [ 05/Dec/09 ]

I understand you, sometimes adopting a framework can be a pain

Problem is coming from the lines:

if ($load) {
$old = $this->get($fieldName, $load);
} else {
$old = $this->_data[$fieldName];
}

in _set method of Doctrine_Record. Here it calls get('data') method and your problem occurs.

Speaking of solution for this I'm not sure what is a way - field name "data" is reserved in Doctrine mainly because there is a method set/getData. However, in the same way a lot of fields can create this problem - just search for methods staring with get and you will find a bunch of them. All these will fail if your column is named the same.
From my point of view, it is how Doctrine is written and it's quite hard to change it now - you have getX for both your custom mutators and Doctrine methods as well. I don't know any possible way how to distinguish between them and only possible way seems to be that option ACCESSOR_OVERRIDE which only means that you need to register your custom code as mutators (very easy).

I didn't managed to find a documentation about this, so I guess we need to wait for someone in a higher level to comment. Right now I see it as invalid/won't fix mainly because it would require a major rewrite of a lot code to remove that ambiguity between method names and I would suggest disabling override, but it's just me

Comment by Jamie Learmonth [ 05/Dec/09 ]

This should get picked up in the generator classes and the developer should be notified as this error occurring at runtime is a real time consumer to debug.

Comment by Jonathan H. Wage [ 07/Dec/09 ]

Can you test this patch? It will throw an exception if you use a invalid field name:

Index: lib/Doctrine/Import/Builder.php
===================================================================
--- lib/Doctrine/Import/Builder.php	(revision 6882)
+++ lib/Doctrine/Import/Builder.php	(working copy)
@@ -508,9 +508,25 @@
      */
     public function buildColumns(array $columns)
     {
+        $manager = Doctrine_Manager::getInstance();
+        $refl = new ReflectionClass($this->_baseClassName);
+
         $build = null;
         foreach ($columns as $name => $column) {
             $columnName = isset($column['name']) ? $column['name']:$name;
+            if ($manager->getAttribute(Doctrine_Core::ATTR_AUTO_ACCESSOR_OVERRIDE)) {
+                $e = explode(' as ', $columnName);
+                $fieldName = isset($e[1]) ? $e[1] : $e[0];
+                $classified = Doctrine_Inflector::classify($fieldName);
+                $getter = 'get' . $classified;
+                $setter = 'set' . $classified;
+
+                if ($refl->hasMethod($getter) || $refl->hasMethod($setter)) {
+                    throw new Doctrine_Import_Exception(
+                        sprintf('When using the attribute ATTR_AUTO_ACCESSOR_OVERRIDE you cannot use the field name "%s" because it is reserved by Doctrine. You must choose another field name.', $fieldName)
+                    );
+                }
+            }
             $build .= "        ".'$this->hasColumn(\'' . $columnName . '\', \'' . $column['type'] . '\'';
 
             if ($column['length']) {
Comment by Massimiliano Torromeo [ 08/Dec/09 ]

I can test the patch in a couple of days, I'll post the results here.
Thanks.

Comment by Massimiliano Torromeo [ 31/Dec/09 ]

Sorry for the long delay. I applied the patch but I don't know when it is supposed to throw the exception.
It doesn't warn on existing databases does it?

Comment by Pawel [ 13/Jan/10 ]

Try to modify file Doctrine/lib/Doctrine/Record.php at line: 1433
I don't know if this is the best solution but works for me.
if ($load) {
if ($fieldName == 'data')

{ $old = $this->get($fieldName, $load); $old = $old['data']; }

else

{ $old = $this->get($fieldName, $load); }

} else

{ $old = $this->_data[$fieldName]; }
Comment by Jonathan H. Wage [ 02/Mar/10 ]

It only throws exceptions when you build your classes.

Comment by Thomas Keller [ 12/Mar/10 ]

The exception doesn't work for me either, though the field(s) which make problems here are `name` and `description`. More information can be found here: <http://github.com/sympal/sympal/issues/issue/7/#comment_157161>





[DC-317] Using NestedSet behavior, createRoot function doesn't behave as expected with string multiple root key Created: 03/Dec/09  Updated: 07/Dec/09  Resolved: 07/Dec/09

Status: Closed
Project: Doctrine 1
Component/s: Behaviors, Nested Set
Affects Version/s: 1.2.0
Fix Version/s: 1.2.1

Type: Bug Priority: Major
Reporter: Julien G Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Using Symfony 1.4 and MySQL



 Description   

I have defined this model :

 
Page:
  options: { type: InnoDB, collate: utf8_unicode_ci, charset: utf8 }
  columns:
    topic:       { type: string(32), notnull: true }
    title:        { type: string(255), notnull: true }
  actAs:
    NestedSet:      { hasManyRoots: true, rootColumnName: topic }

And use this code (database is empty) :

<?

$page = new Page;
$page->topic = 'my-topic';
$page->title = 'My Title';
$page->save();

print_r( $page->topic );  // OK, here it's perfect

Doctrine::getTable('Page')->getTree()->createRoot( $page );

print_r( $page->topic ); // Now topic == 1 . It's buggy !


Doctrine::getTable('Page')->getTree()->fetchTree( 'my-topic' ); // Buggy : return false !

?>

Let me know if you need more explainations,
julien






[DC-323] when inserting a record into sql server (via odbc) doctrine fails to get last inserted ID Created: 03/Dec/09  Updated: 15/Mar/10  Resolved: 15/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Record
Affects Version/s: 1.2.0
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: aiso haikens Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

windows XP SP3, SQL server version
[major] => 9
[minor] => 00
[patch] => 4035
[extra] =>
[native] => Microsoft SQL Server 2005 - 9.00.4035.00 (Intel X86)
Nov 24 2008 13:01:59
Copyright (c) 1988-2005 Microsoft Corporation
Express Edition on Windows NT 5.1 (Build 2600: Service Pack 3))


Attachments: Text File ff.txt     Text File mssql.patch     Text File mssql2.patch    

 Description   

in Doctrine/Sequence/Mssql.php the function lastInsertId() fails to retrieve the last inserted ID when inserting a record. Because the major release of my sql server is bigger than 8, it chooses $query = 'select SCOPY_IDENTITY()' which does not return a number (in fact it does not return anything), although the record IS inserted succesfully. The backtrace is attached.
If, on the other hand, I force doctrine to use 'select @@IDENTITY' the query does return the correct number and everything goes fine!
So I think the conditions which query to choose is incorrect. I tried both queries in SQL server itself and both queries returned the right number. But one of them gets lost somewhere when using it in doctrine.



 Comments   
Comment by Juozas Kaziukenas [ 03/Dec/09 ]

Microsoft SQL Server works in a such way, that different things have different scopes. Running query as prepared statement and then executing it results in different scope, hence running "select scope_identity()" after this query returns nothing. This is expected behaviour, and this is how Microsoft SQL Server should work.

To overcome this issue, I used a popular "hack" (maybe not really a hack) - add this query to the actual query (more here http://forums.devshed.com/ms-sql-development-95/insert-and-return-the-primary-key-232783.html or all other the web):

INSERT INTO X VALUES(1,1,2); SELECT SCOPE_IDENTITY();

Only using this way, I managed to make my component (Zend_Db_Adapter_Sqlsrv) to work. However, since Doctrine is very different and INSERT method is processed in completely different fashion I don't think that there is a way to overcome this issue.

Comment by aiso haikens [ 03/Dec/09 ]

unfortunately, retrieving the lastInsertedId() is part of the insert() functionality. So an exception is thrown everytime I try to insert a new record, which I must overcome (the record is by the way perfectly added to the db)

For me there is a perfect workaround: just use 'select @@IDENTITY' which works flawlessly.

So this is the point: I think more often 'select @@IDENTITY' must be chosen over 'select SCOPY_IDENTITY()' 'cause the latter does not (always?) return the id.

Comment by Juozas Kaziukenas [ 03/Dec/09 ]

I googled some more:

http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
http://beyondrelational.com/blogs/jacob/archive/2009/02/05/sql-server-identity-scope-identity-and-ident-current.aspx

Basically @@IDENTITY works in most cases, but it can go very wrong if you have triggers or stuff like that (which is not that rare in mssql world).

However, since with scope_identity() there are problems, I would say that Doctrine should use @@IDENTITY, because SCOPE_IDENTITY() will never return a value. Just impossible to fix.

Comment by aiso haikens [ 04/Dec/09 ]

Ah, I see, you are right, @@IDENTITY has to many drawbacks.

But in the first link you provided was the answer to overcome scope and trigger problems: the best option should be to actually use 'select IDENT_CURRENT('table_name')'. I just tested it and it works perfect! You only need to pass the table name in UnitOfWork.php in case the driver is mssql.

Comment by Juozas Kaziukenas [ 04/Dec/09 ]

I've attached a possible fix.

Test it if you can and when approved I will commit it.

Comment by aiso haikens [ 09/Dec/09 ]

I tested your patch, but it didn't work since the $table var is empty in my case. This is because the function _assignIdentifier() in UnitOfWork won't set the $seq var in case of 'mssql'. So first of all we need to pass the table name to this function like this in UnitOfWork line 925:

+ } elseif ($driver == 'oracle' || $driver == 'mssql')

{ $seq = $table->getTableName(); }

$id = $this->conn->sequence->lastInsertId($seq);

And furthermore I need to quote the table name before it worked like this in Mssql line 141:

$query = 'SELECT IDENT_CURRENT(\'' . $this->conn->quoteIdentifier($table) . '\')';

After these changes it worked. But don't you think we have to get rid of the SCOPE_IDENTITY entirely?
I attached this patch.

Comment by aiso haikens [ 19/Dec/09 ]

OK, what to do next? The last patch works fine for me. It seems to be the solution to the problem. So, can I check it in? Or should someone else do this? Or do I simply set the status to 'resolve' and someone else does the rest?

Comment by Craig Marvelley [ 03/Mar/10 ]

I tried the last patch and it works fine for me on SQL Server 2005/2008. +1 for committing it

Comment by Jonathan H. Wage [ 15/Mar/10 ]

Thanks for everyones work on this issue.

Comment by Brian B. [ 15/Mar/10 ]

Tried the patch and it works on SQL Server 2005 as well. Lots of fun trying to find it. Thanks for the fix.





[DC-318] Doctrine_Table::find(x) fails for odbc/mssql connection due to limit() clause Created: 03/Dec/09  Updated: 22/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.0
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: aiso haikens Assignee: Jonathan H. Wage
Resolution: Duplicate Votes: 0
Labels: None
Environment:

windows XP SP3


Attachments: Text File ff.txt     Text File mssqlimit.patch     Text File mssqllimit.patch     Text File mssqlllimit2.patch    
Issue Links:
Duplicate
is duplicated by DC-289 Using MSSQL connection the find metho... Closed

 Description   

call that fails is Doctrine::getTable('Building')->find(1). With mysql all is fine, but if I use MSSQL via odbc (SQL Native Client) I get an exception saying:
SQLSTATE[22018]: Invalid character value for cast specification: 206 [Microsoft][SQL Native Client][SQL Server]Er is een conflict met het type operand ontstaan: text is incompatibel met int (SQLExecute[206] at ext\pdo_odbc\odbc_stmt.c:254)
see attached stacktrace.
So find(1) fails but a call to e.g. findAll() works fine.

I found out that if I leave out the limit(1) from the function find() on line 1602 it gives me the correct object and no exception!
So actually what goes wrong is the limit(1) clause in this call:
$object = Doctrine_Query::create()>from('Building b')>where('b.id = 1')>limit(1)>fetchOne();
with getSqlquery() this becomes:
SELECT TOP 1 [inner_tbl].[id] AS [b__id] FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[version] AS [b__version], [b].[name] AS [b__name], [b].[number] AS [b__number], [b].[title_nl] AS [b__title_nl], [b].[title_en] AS [b__title_en], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)) AS [inner_tbl]

If executed with sqlcmd.exe this gives an error saying 'no columnname id', what seems to be correct since it should be [inner_tbl].[b__id] iso [inner_table].[id], so I suspect that the modifyLimitQuery() function in Connection/Mssql.php is not correct either.

I can work around this problem by doing a fetchOne() iso find().



 Comments   
Comment by Juozas Kaziukenas [ 05/Dec/09 ]

This is because of:

$field_array = explode(',', $fields_string);
$aux2 = explode('.', $field_array[0]);
$key_field = trim(end($aux2));

With query like SELECT t.id as t__id FROM X it works like this:

SELECT t.id as t__id FROM X – >
t.id as t__id -->
array('t.id as t__id') -->
array('t', '.id as t__id')

Which is wrong. It should split on "as" an then use it.

I created a patch for this, which should make it work. Test it if you can and I hopefully it will be included into source.

Comment by Jonathan H. Wage [ 07/Dec/09 ]

The patch looks good it just doesn't follow the coding standards. $variableName not $variable_name and

}
else
{

Should be

} else {

You might want to read up on the Doctrine coding standards. Whenever you commit something you must make 100% sure that it follows the standards. If you fix the coding standards in the patch you can commit it.

Comment by Juozas Kaziukenas [ 07/Dec/09 ]

I reattached updated patch, please review if that's what you meant and I will commit it. Variables names were already there, but I fixed them now

Comment by Michael Card [ 09/Dec/09 ]

All the if statements are unnecessary, look a few lines above, the 2-3 lines handle splitting on the as and "." without all the if statements. Related to issue DC-289

Comment by Juozas Kaziukenas [ 09/Dec/09 ]

Yes, somehow missed that one. This one should fix it

Comment by Juozas Kaziukenas [ 09/Dec/09 ]

I looked at DC-289 and it seems to be the same thing as this error. So I suggest closing this as duplicate and fixing that one with a patch provided.

Comment by aiso haikens [ 09/Dec/09 ]

I agree, it is a duplicate of DC-289. I will add my comments about this patch to that one.

Comment by Michael Card [ 18/Dec/09 ]

Should be closed as duplicate.

Comment by Gilberto [ 22/Mar/10 ]

Hello everyone, i'm new here but i'm having the same problem, but i'm not clear about the fixing, please could someone telme realy how can i patch the select sql problem whit mssql, i'm using symfony 1.4 and mssql server 2005, and when i do:

Doctrine_Query::CREATE()
->select('u.username')
->from('User u')
->execute();

then i get the messagge error:
SQLSTATE[HY000]: General error: 10007 Invalid
column name...

to resolve this is very important for me.

sorry my english





[DC-314] length option ignored in addColumn method in Doctrine 1.2 migrations Created: 02/Dec/09  Updated: 02/Dec/09  Resolved: 02/Dec/09

Status: Closed
Project: Doctrine 1
Component/s: Migrations
Affects Version/s: 1.2.0
Fix Version/s: 1.2.1

Type: Bug Priority: Major
Reporter: Tom Boutell Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Symfony 1.3



 Description   

I am using http://doctrine.mirror.svn.symfony-project.com/branches/1.2/lib and saw this problem with revision 6806.

The 'length' parameter in the options array seems to be
ignored by addColumn in Doctrine 1.2 migrations. No matter what we specified for
'length' we got a bigint in MySQL, resulting in failure later when we
tried to add a foreign key because we needed a 4-byte integer. There
does not seem to be any documentation of what is valid in the options
array when calling addColumn, however I see that length is still used
when passing an apparently identical options array for a particular
column when calling createTable.

That is, this code:

$this->addColumn('pg_event_request', 'event_id', 'integer',
array('length' => 4));

Does not work properly in Doctrine 1.2 (you get a bigint in MySQL).

We were able to work around it by implementing a migrate() method
instead, passing 4 as the final argument (there doesn't seem to be
clear documentation of this final argument but in the example in the
documentation it is the length of a string column, and sure enough it
does the same thing for an integer). Passing 4 here worked, we got a
4-byte integer.



 Comments   
Comment by Jonathan H. Wage [ 02/Dec/09 ]

I just fixed this here hehe

http://trac.doctrine-project.org/changeset/6842

Also, the function signature in 1.2 is:

    public function addColumn($tableName, $columnName, $type, $length = null, array $options = array())

It has the $length argument, but you can still pass the length via the options. In the end all that information is just in one array.





[DC-302] Issues when using automatic relations ordering through 'orderBy' param in m2m relations Created: 01/Dec/09  Updated: 01/Dec/09  Resolved: 01/Dec/09

Status: Closed
Project: Doctrine 1
Component/s: Record, Relations
Affects Version/s: 1.2.0
Fix Version/s: 1.2.1

Type: Bug Priority: Major
Reporter: Maciej Hołyszko Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 2
Labels: None
Environment:

php 5.3/win, doctrine 1.2 svn, ATTR_QUOTE_IDENTIFIER = true, ATTR_USE_DQL_CALLBACKS = true


Attachments: File DC302TestCase.php    

 Description   

Partially related to DC-240.

I found some additional problems, mainly with self-referenced relations.
I use ACL system with multiple inheritance, where order of inherited elements matters.
Here we have (Role <- m2m orderBy position - > Role) and (User < - m2m orderBy position -> Role):

class Role extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->hasColumn('name', 'string', 64);
	}
	
	public function setUp()
	{
		$this->hasMany('User as Users', array('local' => 'id_role', 'foreign' => 'id_user', 'refClass' => 'UserRole'));
		$this->hasMany('Role as Parents', array('local' => 'id_role_child', 'foreign' => 'id_role_parent', 'refClass' => 'RoleReference', 'orderBy' => 'position'));
		$this->hasMany('Role as Children', array('local' => 'id_role_parent', 'foreign' => 'id_role_child', 'refClass' => 'RoleReference'));
	}
}

class RoleReference extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->hasColumn('id_role_parent', 'integer', null, array('primary' => true));
		$this->hasColumn('id_role_child', 'integer', null, array('primary' => true));
		$this->hasColumn('position', 'integer', null, array('notnull' => true));
	}
	
	public function setUp()
	{
		$this->hasOne('Role as Parent', array('local' => 'id_role_parent', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
		$this->hasOne('Role as Child', array('local' => 'id_role_child', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
	}
}

class User extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->hasColumn('username', 'string', 64, array('notnull' => true));
		$this->hasColumn('password', 'string', 128, array('notnull' => true));
	}
	
	public function setUp()
	{
		$this->hasMany('Role as Roles', array('local' => 'id_user', 'foreign' => 'id_role', 'refClass' => 'UserRole', 'orderBy' => 'position'));
	}
}

class UserRole extends Doctrine_Record
{
	public function setTableDefinition()
	{
		$this->hasColumn('id_user', 'integer', null, array('primary' => true));
		$this->hasColumn('id_role', 'integer', null, array('primary' => true));
		$this->hasColumn('position', 'integer', null, array('notnull' => true));
	}
	
	public function setUp()
	{
		$this->hasOne('User', array('local' => 'id_user', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
		$this->hasOne('Role', array('local' => 'id_role', 'foreign' => 'id', 'onDelete' => 'CASCADE'));
	}
}

Sample data:

$role1 = new Role();
$role1->name = 'admin'; // id: 1
$role1->save();

$role2 = new Role();
$role2->name = 'publisher'; // id: 2
$role2->save();

$role3 = new Role();
$role3->name = 'reviewer'; // id: 3
$role3->save();

$role4 = new Role();
$role4->name = 'mod'; // id: 4
$role4->save();

// reviewer inherits from admin, mod, publisher - in that order
$role3->Parents[] = $role1;
$role3->Parents[] = $role4;
$role3->Parents[] = $role2;
$role3->save();

// update positions
$query = Doctrine_Query::create()
	->update('RoleReference')
	->set('position', '?', 0)
	->where('id_role_child = ?', 3)
	->andWhere('id_role_parent = ?', 1)
	->execute();
$query = Doctrine_Query::create()
	->update('RoleReference')
	->set('position', '?', 1)
	->where('id_role_child = ?', 3)
	->andWhere('id_role_parent = ?', 4)
	->execute();
$query = Doctrine_Query::create()
	->update('RoleReference')
	->set('position', '?', 2)
	->where('id_role_child = ?', 3)
	->andWhere('id_role_parent = ?', 2)
	->execute();
	

// add test user
$user = new User();
$user->username = 'test';
$user->password = 'test';
$user->fromArray(array('Roles' => array(4, 2)));
$user->save();
// update positions
$query = Doctrine_Query::create()
	->update('UserRole')
	->set('position', '?', 0)
	->where('id_user = ?', 1)
	->andWhere('id_role = ?', 4)
	->execute();
$query = Doctrine_Query::create()
	->update('UserRole')
	->set('position', '?', 1)
	->where('id_user = ?', 1)
	->andWhere('id_role = ?', 2)
	->execute();

Now, lazy-loading self-referenced m2m relations seems to be the issue (I know lazy-loading is wrong but it's needed to be like that in some parts of our system):

$role = Doctrine::getTable('Role')->find(3);
print_r($role->Parents->toArray());

The query which is created and executed during lazy-load of Parents relations is as follows:

SELECT role.id AS role__id, role.name AS role__name, role_reference.id_role_parent AS role_reference__id_role_parent, role_reference.id_role_child AS role_reference__id_role_child, role_reference.position AS role_reference__position FROM role INNER JOIN role_reference ON role.id = role_reference.id_role_parent WHERE role.id IN (SELECT id_role_parent FROM role_reference WHERE id_role_child = ?) ORDER BY role.id ASC, position

(seems a little strange as there are no automatically generated aliases e.g. r1, r2 etc. but whole table names)
The result is ordered by role.id first, then by position (without any alias and that could be an additional problem in some cases)

The result is: (as you can see the order of roles is 1, 2, 4 (positions: 0, 2, 1) instead of 1, 4, 2)

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => admin
            [RoleReference] => Array
                (
                    [0] => Array
                        (
                            [id_role_parent] => 1
                            [id_role_child] => 3
                            [position] => 0
                            [Parent] => 
                        )

                )

        )

    [1] => Array
        (
            [id] => 2
            [name] => publisher
            [RoleReference] => Array
                (
                    [0] => Array
                        (
                            [id_role_parent] => 2
                            [id_role_child] => 3
                            [position] => 2
                            [Parent] => 
                        )

                )

        )

    [2] => Array
        (
            [id] => 4
            [name] => mod
            [RoleReference] => Array
                (
                    [0] => Array
                        (
                            [id_role_parent] => 4
                            [id_role_child] => 3
                            [position] => 1
                            [Parent] => 
                        )

                )

        )

)

It is NOT an issue with lazy-loading m2m relations between two different models:

$user = Doctrine::getTable('User')->find(1);
print_r($user->Roles->toArray());

The query generated seems to be correct: (well except the lack of an alias in front of position column in ORDER BY clause)

SELECT `r`.`id` AS `r__id`, `r`.`name` AS `r__name`, `u`.`id_user` AS `u__id_user`, `u`.`id_role` AS `u__id_role`, `u`.`position` AS `u__position` FROM `role` `r` LEFT JOIN `user_role` `u` ON `r`.`id` = `u`.`id_role` WHERE (`u`.`id_user` IN (?)) ORDER BY position

It works well for self-referenced relations where relation are defined in DQL e.g.:

$query = Doctrine_Query::create()
	->from('Role r')
	->leftJoin('r.Parents rp')
	->orderBy('r.name ASC')
	->where('r.id = ?', 3);
	
var_dump($query->getSqlQuery());
$result = $query->fetchOne();

print_r($result->Parents->toArray());

To sum up:
1. orderBy in m2m self-referenced relations does not work when they are lazy-loaded
2. lack of table alias for orderBy column when lazy-loading m2m relations between separate models (possibly not an issue?)

I am not sure if the first one could be fixed at all, due to specific query construction? If not, I would be glad to see a possible workaround for this problem.

Thanks in advance.



 Comments   
Comment by Maciej Hołyszko [ 01/Dec/09 ]

Attached test case. I did not know how to test the second issue - is there a db profiler available during unit testing?

Comment by Jonathan H. Wage [ 01/Dec/09 ]

Thanks for the report and test case. I made a change and your test case passes now.





[DC-305] Oracle adapter statement closeCursor() is not working properly Created: 01/Dec/09  Updated: 01/Dec/09  Resolved: 01/Dec/09

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.0
Fix Version/s: 1.2.1

Type: Bug Priority: Major
Reporter: Juozas Kaziukenas Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

Close cursor method cleans up non-existing array $bind_params, correct variable name is $bindParams. (comment of $bindParams is wrong to because it also speaks about $bind_params)

Now:

public function closeCursor()
{
$this->bind_params = array();
return oci_free_statement($this->statement);
}

Fix:

public function closeCursor()
{
$this->bindParams = array();
return oci_free_statement($this->statement);
}






[DC-298] Doctrine_Cache_Driver : array_search() expects parameter 2 to be array, boolean given at line 283 Created: 27/Nov/09  Updated: 01/Dec/09  Resolved: 01/Dec/09

Status: Closed
Project: Doctrine 1
Component/s: Caching
Affects Version/s: 1.2.0-RC1
Fix Version/s: 1.2.1

Type: Bug Priority: Major
Reporter: Benoît Guchet Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: File Doctrine_Cache_Array.doDelete.new    

 Description   

Doctrine_Cache_Driver::fetch() is supposed to return a string, but an array_search() is made on it by Doctrine_Cache_Driver::_deleteKey() (at line 283).



 Comments   
Comment by Jonathan H. Wage [ 30/Nov/09 ]

I don't quite understand. Can you explain more?

Comment by Jonathan H. Wage [ 30/Nov/09 ]

Reading your description it doesn't make any sense. Re-open if you have a better more clear description of the problem.

Comment by Benoît Guchet [ 30/Nov/09 ]

It's not very complicated :

In Doctrine_Cache_Driver::_deleteKey, you do array_search() with the array $keys as haystack:

$keys = $this->fetch($this->_cacheKeyIndexKey);
$key = array_search($key, $keys);

But $keys is a string, because Doctrine_Cache_Driver::fetch returns a string (or false) :

/**

  • Fetch a cache record from this cache driver instance
    *
  • @param string $id cache id
  • @param boolean $testCacheValidity if set to false, the cache validity won't be tested
  • @return string cached datas (or false)
    */
    public function fetch($id, $testCacheValidity = true)

You can't make an array_search on a string.

I can't be more clear

edit : You may tell me that the PHPdoc is wrong : but the problem still appears when ::fetch returns false.

Comment by Jonathan H. Wage [ 30/Nov/09 ]

The api documentation is wrong, fetch always returns the data structure that was originally stored. So in this case it is an array.

Comment by Benoît Guchet [ 30/Nov/09 ]

Ok i've anticipated this answer

So Cf. edit of my last comment.

Comment by Jonathan H. Wage [ 30/Nov/09 ]

I updated the API doc blocks.

Comment by Benoît Guchet [ 01/Dec/09 ]

Sorry, I reopen this issue again because I still encounter it.

I've watched it deeper to make it reproductible :

I'm using Doctrine_Cache_Array.
The problem simply appears when you try to delete a cache entry that does not exist.

example :

$cache = new Doctrine_Cache_Array();
$cache->delete(45);

Comment by Benoît Guchet [ 01/Dec/09 ]

Patch to Doctrine_Cache_Array::_doDelete() so that it returns false if the entry does not exist.





[DC-289] Using MSSQL connection the find method for models does not work Created: 25/Nov/09  Updated: 02/Mar/10  Resolved: 02/Mar/10

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.0-RC1
Fix Version/s: 1.2.2

Type: Bug Priority: Major
Reporter: Trevor Lanyon Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 3
Labels: None
Environment:

php 5.3.1,
Symfony 1.4.0-DEV
Doctrine 1.2.0-RC1
pdo_mssql (libdb)


Attachments: File Mssql-Patch-20091218.php     File Mssql-Patch-20091221.php     File Mssql-Patch-20091222.php    
Issue Links:
Duplicate
duplicates DC-318 Doctrine_Table::find(x) fails for odb... Closed

 Description   

using a doctrine generated class's find method produced erroneous SQL such as:

SELECT TOP 1 [inner_tbl].[id] AS [b__id] FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], [b].[alias] AS [b__alias], [b].[ip] AS [b__ip], [b].[operator_id] AS [b__operator_id], [b].[cell_id] AS [b__cell_id], [b].[latitude] AS [b__latitude], [b].[longtitude] AS [b__longtitude], [b].[community_read] AS [b__community_read], [b].[community_write] AS [b__community_write], [b].[last_found_at] AS [b__last_found_at], [b].[active] AS [b__active], [b].[type] AS [b__type], [b].[poll_mac_behind_sus] AS [b__poll_mac_behind_sus], [b].[created_at] AS [b__created_at] FROM [basestation] [b] WHERE ([b].[id] = '2')) AS [inner_tbl]

commenting out the following line (193) in' function modifyLimitQuery' for lib/Doctrine/Connection/Mssql.php

$query = preg_replace('/^'.$selectRegExp.'/i', $selectReplace . 'TOP ' . ($count + $offset) . ' ', $query);

//$query = 'SELECT TOP ' . $count . ' ' . $this->quoteIdentifier('inner_tbl') . '.' . $key_field . ' FROM (' . $query . ') AS ' . $this->quoteIdentifier('inner_tbl');

if ($orderby !== false) {

It appears to have worked. This method was part of jwage's commit for change set 6795 (http://trac.doctrine-project.org/changeset/6795/branches/1.2/lib/Doctrine/Connection/Mssql.php) so there must be a reason for this change. This is very preliminary. If the change works there is a considerable amount of refactoring that way be done. I will commit a proper patch once I am able to test exhaustively, at the moment this is a show stopper and I need to continue development.



 Comments   
Comment by Michael Card [ 26/Nov/09 ]

Trevor,

I had worked on these changes the jwage committed as I couldn't find any way how the old code worked. Did this code work in versions before 1.2.0-RC1 or are you just finding this using the new version?

What code are you using for the find? The code works okay when running a normal dql query.

Mike

Comment by Trevor Lanyon [ 26/Nov/09 ]

Michael,

It seems as though I first encountered the problem after I did an svn update. I can assume that it was changeset 6795 as the problem is created in lib/Doctrine/Connection/Mssql.php and the weeks before changeset 6795 the exact same code worked.

The dql does work very well. I don't really use find methods too often as I like to bring my models back with as few loads as possible and most of my models aren't flat enough to use a find.

I found the error mostly with the pages that were generated by symonfy as doctrine:generate-model generates lines such as : $this->forward404Unless($Basestation = Doctrine::getTable('Basestation')>find(array($request>getParameter('id'))), sprintf('Object Basestation does not exist (%s).', $request->getParameter('id'));

The problem is very obvious. The changeset removed the 'SELECT *' and tried to do a 'SELECT

{key}'. The {key}

is referring to the raw column name but is selecting from a subquery that has already aliased the

{key} field so it comes back with an error. I imagine there's a reason for only selecting the {key}

but I haven't encountered that yet. Once I have code that breaks with my change I will be able to implement a better fix.

For now it seems to be working.

Comment by Michael Card [ 30/Nov/09 ]

Hey Trevor,

Commenting out the line like you did won't work when using both a limit and an offset, you have to have the inner and outer queries to have the limit and offset work correctly.

Regular dql does a "select ... from table where key in (limit suquery here)" for the limit subquery has to only return 1 field.

What did you mean by "The

{key} is referring to the raw column name but is selecting from a subquery that has already aliased the {key}

field so it comes back with an error." Maybe I can work out some code that works in all situations.

Mike

Comment by Trevor Lanyon [ 30/Nov/09 ]

Hi Micheal,

"Commenting out the line like you did won't work when using both a limit and an offset, you have to have the inner and outer queries to have the limit and offset work correctly."

– exactly.

I finally had need for a limit on Friday and had started working on a proper adjustment. If it is something that you might be able to do that would be fantastic.

"What did you mean by "The

{key} is referring to the raw column name but is selecting from a subquery that has already aliased the {key}

field so it comes back with an error." Maybe I can work out some code that works in all situations."

If you look at the SQL that is in the first comment I appended you'll see:

'
SELECT TOP 1 [inner_tbl].[id] AS [b__id] FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], ..................
'

Which will cause an error as the first statement "SELECT TOP [inner_tbl].[id] AS [b__id] FROM " tries to select [inner_tbl].[id] however [inner_tbl].[id] does not exist, it has been aliased to [inner_tbl].[[b__id] as per the SQL in the inner join.

I hope that is more clear.

I'm going to fumble around the code a little this morning and see if I can come up with something.

Thank you Michael.

Comment by Jonathan H. Wage [ 07/Dec/09 ]

Any updates or new information on this issue?

Comment by Michael Card [ 09/Dec/09 ]

I'm working on a fix, have something in a couple days.

Comment by aiso haikens [ 09/Dec/09 ]

Hi, I will put my comments to DC-318 here since it is a duplicate of this one.

the last patch of DC-318 gives this sql statement:
SELECT TOP 1 [inner_tbl].[b__id] FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[version] AS [b__version], [b].[name] AS [b__name], [b].[number] AS [b__number], [b].[title_nl] AS [b__title_nl], [b].[title_en] AS [b__title_en], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)) AS [inner_tbl]

which is a correct sql statement if executed with sqlcmd.exe. But it still gives me the same exception as shown in the backtrace attached to DC-318.
But isn't it strange that just the id is return iso the complete record?? If I remove the limit(1) clause from the find function in Table.php it give this sql statement and works perfectly:
SELECT [b].[id] AS [b__id], [b].[version] AS [b__version], [b].[name] AS [b__name], [b].[number] AS [b__number], [b].[title_nl] AS [b__title_nl], [b].[title_en] AS [b__title_en], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)

Comment by Michael Card [ 10/Dec/09 ]

Its more complicated, I'll write a patch this weekend.

It needs to be broken out to use seperate functions for modifyLimitQuery and modifyLimitSubQuery, the one function is trying to handle two different things. For a simple dql statement the modifyLimitQuery needs to return all fields. In a complex dql query, it needs to return the key field only as it is used as part of the where statement in the overall query.

Comment by Michael Card [ 18/Dec/09 ]

I'm attaching a patch Mssql-Patch-20091218.php. This should fix all the find problems and the pager problems.

Trevor and Aiso, can you test the patch before Jon applies it. I've tested it using regular dql querying, it needs to be tested using the find function and also using the pager. Two things to look for - does it work obviously, which means it fixed the field name error, and second, does it return all the fields, before it was only returning the id field.

Jon - To avoid tons of code duplicaton between modifyLimitQuery and modifyLimitSubQuery, I added a parameter to modifyLimitQuery, if this is no good, we can change it to just duplicate the code between the two functions.

Mike

Comment by aiso haikens [ 19/Dec/09 ]

Thanks Michael for the patch. I just tested it and it doesn't work. Still the same odbc exception when executing the sql statement. The exception goes like this:
SQLSTATE[22018]: Invalid character value for cast specification: 206 [Microsoft][SQL Native Client][SQL Server]Er is een conflict met het type operand ontstaan: text is incompatibel met int (SQLExecute[206] at ext\pdo_odbc\odbc_stmt.c:254)

the query that is finally produced by modifyLimitQuery() (so the one that fails) is:

SELECT * FROM (SELECT TOP 1 [inner_tbl].[b__id] FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)) AS [inner_tbl]) AS [outer_tbl]

Note that if I return the $query on line 194, just after the preg_replace, everything is fine. In that case the sql statement is (so basically the inner most select):

SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)

so, I have 2 questions:

  • why not return this last (working) query in this case? Why bother with doing the 3 nested selects?
  • I don't see how the nested queries can work in the first place since the second query selects only the id, iso the complete entry. I tried this : 'SELECT TOP 1 [b].[id] AS [b__id] FROM [building] [b] WHERE ([b].[id] = ?)' and although I do not get an exception I don't get the right record! But not very suprising to me since you return only an id.

Note that if I run the failing query (so the 3 nested selects) in SQL Server Manager I get the id without problems, so the statement itself is correct (although I do not think it is correct only to return the id). So maybe this is a problem in pdo_odbc only?

Comment by aiso haikens [ 19/Dec/09 ]

Hi Michael, I completely missed the rest of your last comment, sorry about that: so my questions are a bit awkward. I read also that in some cases it is necessary to use the nested selects.
To comment on your 2 things to look for: it does work in the sense that the field name error is solved, but wrt your second thing: maybe all fields are return in the end but I could not test this properly since the pdo_odbc will not tolerate the nested selects construction so it seems.

Note that I get the same exception when using only 2 selects like this:
SELECT * FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)) AS [outer_tbl]

Comment by aiso haikens [ 20/Dec/09 ]

I figured out that my app suffers from a very old bug in the SQL server client app. See http://bugs.php.net/bug.php?id=36561

It says it cannot handle bound params in a subquery! So I don't know how you fellows make this work??? It basically means that all this code is useless since it will never work for mssql until microsoft comes up with a solution!

I just upgraded from sql server 2005 express to 2008 express to see if that helped but it didn't. So this is a very disturbing bug that is in the code since 2006 and till this day is never solved....

So, are there any versions of mssql server that can handle these subqueries, I wonder? What do you guys use to make this work??? I think the conclusion is that pdo_odbc and doctrine will never work.

Comment by Trevor Lanyon [ 21/Dec/09 ]

Hi Michael and Aiso,

I had ran into that problem with sub query casting integers as strings. That cost me about 4 hours. I had to go into the Query Analyzer to find that pdo_lib was encapsulating the integers in quotation marks (making them strings) even though the query debug window was showing them without encapsulation. Although it is a terrible solution I embedded the integers directly into the SQL. It was the only option and it worked good enough (for now).

I agree that mssql (using pdo_lib for connectivity) might be too limited. As well as the bug you've indicated pdo_lib also limits column names to 30 characters. These limitations are very, very frustrating.

In regards to the patch I'm still generating errors:

SQLSTATE[HY000]: General error: 207 General SQL Server error: Check messages from the SQL Server [207] (severity 16) [(null)]

With the following code:

45 $q = Doctrine::getTable( 'Radiusdat' )->createQuery( 'r' )
46 >where( 'r.username LIKE ?', $this>getUsername( ) )
47 ->orderBy( 'r.callstart DESC' )
48 ->limit( $limit );

The SQL generated looks like this:

SELECT *
FROM (SELECT TOP 5 [inner_tbl].[r__username]
FROM (SELECT TOP 5 [r].[username] AS [r__username]
, [r].[callstart] AS [r__callstart]
, [r].[callend] AS [r__callend]
, [r].[sessid] AS [r__sessid]
FROM [radiusdat] [r]
WHERE ([r].[username] LIKE '')
ORDER BY [r].[callstart] DESC) AS [inner_tbl]
ORDER BY [inner_tbl].[r__callstart] ASC) AS [outer_tbl]
ORDER BY [outer_tbl].[r__callstart] DESC

Running the query manually I get the following:
"Invalid column name 'r__callstart'"

If you look at the SQL you'll see that it is trying to ORDER BY [inner_tbl].[r__callstart] by [inner_tbl].[r__callstart] does not exist, only [inner_tbl].[r__username] exists.

Please let me know if I can test anything else.

Comment by Michael Card [ 21/Dec/09 ]

Trevor - added a new patch, can you give this one a try. I think this should work in both situations now: modify limit queries and modify limit subqueries.

Comment by Trevor Lanyon [ 21/Dec/09 ]

Hi Michael - Tried applying the patch : didn't work (tried applying it to the previously patched then I deleted the file, svn updated and tried applying it still didn't work) so I did it by hand. The results might be wrong because I messed up the application.

It is having a problem now in that it isn't aliasing the outside table, ie:

The application generates this code:
SELECT * FROM ( SELECT TOP 1 * FROM ( SELECT TOP 1 [a].[login_name] AS [a__login_name], [a].[last_login_at] AS [a__last_login_at], [a].[display_name] AS [a__display_name], [a].[created_at] AS [a__created_at] FROM [ad_user] [a] WHERE ([a].[login_name] = 'tlanyon')) AS [inner_tbl]

which is missing a ") as [outer_tbl]"

results of the attempted patch:
[tlanyon@samadams Connection]$ rm Mssql.php
[tlanyon@samadams Connection]$ svn update
Restored 'Mssql.php'
At revision 6971.
[tlanyon@samadams Connection]$ patch Mssql.php Mssql-Patch-20091221.php
(Stripping trailing CRs from patch.)
patching file Mssql.php
patch unexpectedly ends in middle of line
patch: **** unexpected end of file in patch at line 47

Hope this helps.

Comment by Michael Card [ 22/Dec/09 ]

Hi Trevor, patch corrected, I think it was missing a new line at the end. Let me know is it works now. or if it is still not including the ") as [outer_tbl]"

Comment by Trevor Lanyon [ 22/Dec/09 ]

Hi Michael,

The patch applied. Thank you.

The solution did not work however. The below code:

Doctrine::getTable( 'CcmePoll' )
86 ->createQuery( 'p' )
87 ->innerJoin( 'p.CcmeEphoneAct a' )
88 >where( 'p.created_at < ?', $this>start )
89 ->andWhere( 'a.tag = ?', $ePhone['tag'] )
90 ->orderBy( 'p.created_at desc' )
91 ->limit( 1 )
92 ->fetchOne( );

generated this SQL:

SELECT [c].[id] AS [c__id], [c].[type] AS [c__type], [c].[created_at] AS [c__created_at], [c2].[ccme_poll_id] AS [c2__ccme_poll_id], [c2].[tag] AS [c2__tag], [c2].[device_name] AS [c2__device_name], [c2].[registration_state] AS [c2__registration_state], [c2].[active_dn] AS [c2__active_dn], [c2].[activity_status] AS [c2__activity_status], [c2].[keep_alive_count] AS [c2__keep_alive_count], [c2].[pending_reset] AS [c2__pending_reset], [c2].[registration_time] AS [c2__registration_time], [c2].[current_firmware] AS [c2__current_firmware], [c2].[previous_firmware] AS [c2__previous_firmware], [c2].[last_error] AS [c2__last_error], [c2].[observed_type] AS [c2__observed_type], [c2].[login_status] AS [c2__login_status], [c2].[dnd_status] AS [c2__dnd_status], [c2].[debug_status] AS [c2__debug_status], [c2].[media_active] AS [c2__media_active], [c2].[tapi_client] AS [c2__tapi_client], [c2].[media_capability] AS [c2__media_capability], [c2].[remote] AS [c2__remote] FROM [ccme_poll] [c] INNER JOIN [ccme_ephone_act] [c2] ON [c].[id] = [c2].[ccme_poll_id] WHERE [c].[id] IN (SELECT TOP 1 [inner_tbl].[id] FROM (SELECT DISTINCT TOP 1 [c].[id] FROM [ccme_poll] [c] INNER JOIN [ccme_ephone_act] [c2] ON [c].[id] = [c2].[ccme_poll_id] WHERE [c].[created_at] < '2009-12-22 8:0:00' AND [c2].[tag] = '13' ORDER BY [c].[created_at] desc) AS [inner_tbl] ORDER BY [inner_tbl].[ ASC) AND ([c].[created_at] < '2009-12-22 8:0:00' AND [c2].[tag] = '13') ORDER BY [c].[created_at] desc

Without having to go through the whole thing please pay special attention to this, near the bottom of the statement:

AND [c2].[tag] = '13'
ORDER BY [c].[created_at] desc) AS [inner_tbl]
ORDER BY [inner_tbl].[ ASC)

The code is not including the entire field name.

Hope this helps.

Comment by Michael Card [ 22/Dec/09 ]

After attempting to debug this for about 30 minutes, I realized your probably not running 1.2.0RC1, apply the changes in DC-254 and this problem your having should go away.

On another note, does the query that was producing:
SELECT * FROM ( SELECT TOP 1 * FROM ( SELECT TOP 1 [a].[login_name] AS [a__login_name], [a].[last_login_at] AS [a__last_login_at], [a].[display_name] AS [a__display_name], [a].[created_at] AS [a__created_at] FROM [ad_user] [a] WHERE ([a].[login_name] = 'tlanyon')) AS [inner_tbl]
work now?

Comment by Trevor Lanyon [ 22/Dec/09 ]

Hi Micheal,

I'm sorry if I have in anyway wasted your time. The fix http://www.doctrine-project.org/jira/browse/DC-254 has already been applied to my code base (according to the symfony debug window I'm running (Doctrine Version: 1.2.1 which seems to include the modification). I maybe be confused.

Yes. The select without the embedded order by works perfectly now.

Please let me know if I can be more of a help.

Thank you for your attention.

Comment by Michael Card [ 22/Dec/09 ]

No problem at all, I really thought that was the issue

Are you using dblib? If so, edit \lib\Doctrine\Query.php line 1367:
< if ($driverName == 'pgsql' || $driverName == 'oracle' || $driverName == 'oci' || $driverName == 'mssql' || $driverName == 'odbc') {

> if ($driverName == 'pgsql' || $driverName == 'oracle' || $driverName == 'oci' || $driverName == 'mssql' || $driverName == 'odbc' || $driverName == 'dblib') {

Then give it a try again and let me know if we've got it now.

MIke

Comment by Trevor Lanyon [ 22/Dec/09 ]

That did it.

Excellent. Excellent. Excellent.

Thank you.

Comment by Michael Card [ 22/Dec/09 ]

Give it a try on a bucnh of queries and see it you can come up with anything that isn't working (because of this issue ) otherwise, maybe we can finally get this committed.

Mike

Comment by Trevor Lanyon [ 22/Dec/09 ]

Hi Mike,

I've tested it on ten different scenarios ranging from find() to complex dql including inner joins, left joins, orderBy and limit statements.

I have not tested in the example of a pager as I have no need for one. I will create a pager and have an answer for you within 24 hours.

Thanks!

Comment by Trevor Lanyon [ 23/Dec/09 ]

I tested the pager and I had some mixed results.

The pager seemed to only work if you indicate a orderBy clause in the query you send the pager.

I imagine this has to with the strange way one must order results to facilitate the LIMIT X,Y functionality of other (IMHO superior) DBMSs.

I'm expecting this information may make sense to and should suffice for 99% of usage as most people would sort the results when using a pager.

Please let me know if I may help at all.

Thank you again!

Comment by Michael Card [ 23/Dec/09 ]

What sql does it spit out if you don't use an order by statement? Maybe there is a small tweak I can make to get it working in those situations.

Comment by Trevor Lanyon [ 23/Dec/09 ]

The below is an example of the same query for page 1, 2, 3 with first no order by and then order by.

Please let me know if my summary has left out inportant information

Query Used:

68 $query = Doctrine_Query::create()
69 ->from( "Customer c" )
70 ->leftJoin( 'c.Accessdatas a' )
71 ->leftJoin( 'c.SipPhoneServices s' )
72 ->where( $whereSQL );

/*No Order By Page 1
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 20 [c].[id]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email] LIKE '%smith%') AS [inner_tbl])
AND ([c].[email] LIKE '%smith%')

/*No Order By Page 2
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 40 [c].[id]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email] LIKE '%smith%') AS [inner_tbl])
AND ([c].[email] LIKE '%smith%')

/*No Order By Page 3
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 60 [c].[id]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email] LIKE '%smith%') AS [inner_tbl])
AND ([c].[email] LIKE '%smith%')

Query Used:

68 $query = Doctrine_Query::create()
69 ->from( "Customer c" )
70 ->leftJoin( 'c.Accessdatas a' )
71 ->leftJoin( 'c.SipPhoneServices s' )
72 ->where( $whereSQL )
73 ->orderBy( 'c.Name' );

/*Order By Page 1
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 20 [c].[id]
, [c].[name]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email]
LIKE '%smith%'
ORDER BY [c].[name]) AS [inner_tbl]
ORDER BY [inner_tbl].[name] DESC)
AND ([c].[email] LIKE '%smith%')
ORDER BY [c].[name]

/*Order By Page 2
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 40 [c].[id], [c].[name]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email]
LIKE '%smith%'
ORDER BY [c].[name]) AS [inner_tbl]
ORDER BY [inner_tbl].[name] DESC)
AND ([c].[email] LIKE '%smith%')
ORDER BY [c].[name]

/*Order By Page 3
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 60 [c].[id]
, [c].[name]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email] LIKE '%smith%'
ORDER BY [c].[name]) AS [inner_tbl]
ORDER BY [inner_tbl].[name] DESC)
AND ([c].[email] LIKE '%smith%') ORDER BY [c].[name]

Comment by Michael Card [ 23/Dec/09 ]

Was it producing bad sql or just weird results. It looks like the queries for no order by are valid.

Comment by Trevor Lanyon [ 23/Dec/09 ]

The SQL was valid.

Just weird results. Moving through the pages would not move through the results predictably. Moving from page 1 to page 2 would display the same results. Moving from page 2 to page 3 would again show the same results. Moving from page 3 to page four would then show the last page's results (or something similar).

Comment by Michael Card [ 23/Dec/09 ]

Good, weird results is okay, just wanted to make sure the sql wasn't causing errors.

Comment by Michael Card [ 23/Dec/09 ]

@jwage Can you commit the most recent patch, everything is finally working correctly.

Comment by Daniel Anderson Tiecher [ 02/Feb/10 ]

@Michael Card

The issue with limit and offset methods not working properly punched me in the face today. After an hour of going through a lot of ways to simulate them in SQL Server i came up with two ways of doing it:

Default way (the one M$ suggests)
--------------
Create a query that looks like this:

SELECT * FROM (
SELECT TOP $limit * FROM (
SELECT TOP ($limit + $offset) [a].[id] AS [a__id], [a].[id_tipo_produto] AS [a__id_tipo_produto], [a].[nm_produto_base] AS [a__nm_produto_base], [a].[fg_ativo] AS [a__fg_ativo] FROM [ad_produto_base] [a] order by [a__id] ASC
) AS [inner_tbl] ORDER BY 1 DESC
) AS [outer_tbl] ORDER BY 1 ASC

Problem with this solution:
When you are near the end of the paging and queries for the remaining results you will receive all the results from the last page AND some results from the previous one.

Way that I came up with when drinking some tea
----------------------------------------------
Simply add the suffix " WHERE $index > $offset" to the end of the $query variable before wrapping it in its outer selects.

This would produce something along the lines of:
SELECT * FROM (
SELECT TOP 2 * FROM (
SELECT [a].[id] AS [a__id], [a].[id_tipo_produto] AS [a__id_tipo_produto], [a].[nm_produto_base] AS [a__nm_produto_base], [a].[fg_ativo] AS [a__fg_ativo] FROM [ad_produto_base] [a] WHERE $index > $offset
) AS [inner_tbl]
) AS [outer_tbl]

Problem with this solution: your inner select WILL need to have an integer index to compare to the value of $offset. In my case all my tables have an id field so that's not a problem but I guess this would not always be the case. Besides that, I couldn't find a way to retrieve the primary key name (my $index) from inside the method you modified and hardcoded " WHERE id > {$offset}" on it instead.

I'm sure that with my 2 cents we will be able to work out a more reliable solution to this issue.

Cheers,

Comment by Michael Card [ 02/Feb/10 ]

@Daniel

That solution would work of sorting by anything but the id field though, the solution needs to be able to sort by any field. I will take a look at the issue you mentioned, about the last page of the paging results, and see what can be done.

Mike

Comment by Craig Marvelley [ 01/Mar/10 ]

Hello,

I was wondering what the status of this issue was? We're also suffering the pain of trying to get Doctrine working with ODBC and MSSQL, and the patch solved a few bugs for us. Obviously there are still some kinks to be worked out but the driver's unusable in it's current state. If it's a case of needing the pager issue resolved first I'd gladly look at fixing it.

Incidentally, regarding Aiso Haikens' comment above - we've also come up against the binding issue and like Trevor have temporarily got around it by rewriting queries so the parameters are inline rather than bound. Not pleasant. We're investigating whether it can be patched at the PDO driver level but so far no joy. Do you think it would be worth adding our rewrite patch in the meantime so at least queries aren't subject to that bug?

Craig

Comment by Jonathan H. Wage [ 02/Mar/10 ]

I committed the most recent patch and all tests passed. Thanks for everyones work and comments on the issue.

  • Jon




[DC-285] Doctrine_Migration::createForeignKey takes 2 args, documentation says 3 args, code in docs does not work Created: 24/Nov/09  Updated: 25/Nov/09  Resolved: 24/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Migrations
Affects Version/s: 1.0.13, 1.0.14
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Tom Boutell Assignee: Jonathan H. Wage
Resolution: Invalid Votes: 0
Labels: None
Environment:

Symfony 1.2, but using branches/1.0 of Doctrine



 Description   

The documentation here:

http://www.doctrine-project.org/documentation/manual/1_0/en/migrations:writing-migration-classes:available-operations:create-foreign-key

Says that when coding a migration, createForeignKey should take three arguments like so:

this->createForeignKey('table_name', 'email_foreign_key', $definition);

That produces this error:

macintosh-4:pogil boutell$ ./symfony doctrine:migrate
Catchable fatal error: Argument 2 passed to Doctrine_Migration::createForeignKey() must be an array, string given, called in /Users/boutell/Sites/pogil/lib/migration/doctrine/022_eventrequestcreator.class.php on line 17 and defined in /Users/boutell/Sites/pogil/lib/vendor/doctrine/Doctrine/Migration.php on line 487

The source code says:

/**

  • createForeignKey
    *
  • @param string $tableName
  • @param string $constraintName
  • @return void
    */
    public function createForeignKey($tableName, array $definition) { $options = get_defined_vars(); $this->addChange('created_fks', $options); }

I grepped for created_fks and found no references to it except in calls to addChange(), so I don't know where it's consumed or how, so... I don't know what the correct code might look like.

Right now it is not possible to add foreign keys in a migration by following the 1.0.x documentation.



 Comments   
Comment by Jonathan H. Wage [ 24/Nov/09 ]

The documentation is just wrong. The api is correct.

$definition = array(
            'name'          => 'email_foreign_key',
            'local'         => 'email_id',
            'foreign'       => 'id',
            'foreignTable'  => 'email',
            'onDelete'      => 'CASCADE'
);

$this->createForeignKey('table_name', $definition);
Comment by Tom Boutell [ 25/Nov/09 ]

Makes sense. I suppose I should have tried 'name.' (: Thanks for fixing the docs.





[DC-279] Code Corrections For MsSql modifyLimitQuery Created: 23/Nov/09  Updated: 23/Nov/09  Resolved: 23/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.1.5
Fix Version/s: 1.2.0-RC1

Type: Bug Priority: Major
Reporter: Michael Card Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

Below are some code corrections for the modifyLimitQuery. These fixes should also fix DC-37

Code details:

  • Fixed case on sorting orders to match all other syntax.
  • Added additional explode to ensure we only get fieldname and not tablename.fieldname.
  • Added code to determine primary key for use in select statement. There may be a better way of doing this, but not with the input sent to the function I don't think.
  • Removed the outer table (not sure how this could have ever worked) and switched inner table to return only primary key and not all fields.
  • Removed outer table order by logic.

Diff - Old To New:

160c160
<                     $sorts[$i] = (stripos($orders[$i], ' desc') !== false) ? 'desc' : 'asc';
---
>                     $sorts[$i] = (stripos($orders[$i], ' desc') !== false) ? 'DESC' : 'ASC';
171a172
>                     $aux2 = explode('.', end($aux2));
185a187,191
>             $fields_string = substr($query, strlen($selectReplace), strpos($query, ' FROM ') - strlen($selectReplace));
>             $field_array = explode(',', $fields_string);
>             $aux2 = explode('.', $field_array[0]);
>             $key_field = trim(end($aux2));
> 
187c193
<             $query = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $query . ') AS ' . $this->quoteIdentifier('inner_tbl');
---
>             $query = 'SELECT TOP ' . $count . ' ' . $this->quoteIdentifier('inner_tbl') . '.' . $key_field . ' FROM (' . $query . ') AS ' . $this->quoteIdentifier('inner_tbl');
199,212d204
<                 }
<             }
< 
<             $query .= ') AS ' . $this->quoteIdentifier('outer_tbl');
< 
<             if ($orderby !== false) {
<                 $query .= ' ORDER BY '; 
< 
<                 for ($i = 0, $l = count($orders); $i < $l; $i++) { 
<                     if ($i > 0) { // not first order clause 
<                         $query .= ', '; 
<                     } 
< 
<                     $query .= $this->quoteIdentifier('outer_tbl') . '.' . $aliases[$i] . ' ' . $sorts[$i];

Entire New Function:

    public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false)
    {
        if ($limit > 0) {
            $count = intval($limit);
            $offset = intval($offset);

            if ($offset < 0) {
                throw new Doctrine_Connection_Exception("LIMIT argument offset=$offset is not valid");
            }

            $orderby = stristr($query, 'ORDER BY');

            if ($orderby !== false) {
                // Ticket #1835: Fix for ORDER BY alias
                // Ticket #2050: Fix for multiple ORDER BY clause
                $order = str_ireplace('ORDER BY', '', $orderby);
                $orders = explode(',', $order);

                for ($i = 0; $i < count($orders); $i++) {
                    $sorts[$i] = (stripos($orders[$i], ' desc') !== false) ? 'DESC' : 'ASC';
                    $orders[$i] = trim(preg_replace('/\s+(ASC|DESC)$/i', '', $orders[$i]));

                    // find alias in query string
                    $helper_string = stristr($query, $orders[$i]);

                    $from_clause_pos = strpos($helper_string, ' FROM ');
                    $fields_string = substr($helper_string, 0, $from_clause_pos + 1);

                    $field_array = explode(',', $fields_string);
                    $field_array = array_shift($field_array);
                    $aux2 = spliti(' as ', $field_array);
                    $aux2 = explode('.', end($aux2));

                    $aliases[$i] = trim(end($aux2));
                }
            }

            // Ticket #1259: Fix for limit-subquery in MSSQL
            $selectRegExp = 'SELECT\s+';
            $selectReplace = 'SELECT ';

            if (preg_match('/^SELECT(\s+)DISTINCT/i', $query)) {
                $selectRegExp .= 'DISTINCT\s+';
                $selectReplace .= 'DISTINCT ';
            }

            $fields_string = substr($query, strlen($selectReplace), strpos($query, ' FROM ') - strlen($selectReplace));
            $field_array = explode(',', $fields_string);
            $aux2 = explode('.', $field_array[0]);
            $key_field = trim(end($aux2));

            $query = preg_replace('/^'.$selectRegExp.'/i', $selectReplace . 'TOP ' . ($count + $offset) . ' ', $query);
            $query = 'SELECT TOP ' . $count . ' ' . $this->quoteIdentifier('inner_tbl') . '.' . $key_field . ' FROM (' . $query . ') AS ' . $this->quoteIdentifier('inner_tbl');

            if ($orderby !== false) {
                $query .= ' ORDER BY '; 

                for ($i = 0, $l = count($orders); $i < $l; $i++) { 
                    if ($i > 0) { // not first order clause 
                        $query .= ', '; 
                    } 

                    $query .= $this->quoteIdentifier('inner_tbl') . '.' . $aliases[$i] . ' '; 
                    $query .= (stripos($sorts[$i], 'asc') !== false) ? 'DESC' : 'ASC';
                }
            }
        }

        return $query;
    }


 Comments   
Comment by Jonathan H. Wage [ 23/Nov/09 ]

Thanks for the ticket and changes to the function.





[DC-282] Memory Leak in Doctrine_Query_Abstract._getDqlCallbackComponents() Created: 24/Nov/09  Updated: 24/Nov/09  Resolved: 24/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.1.5
Fix Version/s: 1.2.0

Type: Bug Priority: Major
Reporter: Markus Thielen Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PHP 5.2.11, Apache 2.2, Ubuntu Linux 9.1



 Description   

The following iteration shows increasing memory usage:

 $manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine::ATTR_USE_DQL_CALLBACKS, true);
$manager->....connection....

for($i=0; $i<10;$i++) {
  $tx = Doctrine_Query::create()
    ->from('Some_Entity cot')
    ->andWhere('cot.id = ?', $someid)
     ->fetchOne();
			
  $usage = memory_get_usage();
  echo $i.': '.$usage."\n";
}

This results in an exceed-max-memory-fatal (750 MB) with a more complex application i am running that iterates >20,000 times.
I found out that there is a memory leak in Doctrine_Query_Abstract._getDqlCallbackComponents():

...
$copy->getSqlQuery($params);
$componentsAfter = $copy->getQueryComponents();
$copy->free(); //This is the solution
...

Sincerly,
Markus






[DC-276] HAVING does not parse column aliases Created: 21/Nov/09  Updated: 08/Jan/10  Resolved: 23/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.2.0-BETA3
Fix Version/s: 1.2.0-RC1

Type: Bug Priority: Major
Reporter: Andrei Dziahel Assignee: Guilherme Blanco
Resolution: Fixed Votes: 0
Labels: None


 Description   

How to reproduce

$query->having('<aggregate_alias> <operator> <column_alias>').

Expected SQL:

 
... HAVING <internal_aggregate_alias> <operator> a<N>__<column_name>...

Produced SQL

... HAVING <internal_aggregate_alias> <operator> <column_alias> ... /* yes, the same <column_alias> as in ->having() call! */

I've prepared this "real-world example".

Please fix it someone since I'm forced to invent weird workarounds to emulate this behaviour.

Thanks in advance.



 Comments   
Comment by Timo Haberkern [ 08/Jan/10 ]

Doesn't work for me in Symfony 1.3.1, Doctrine 1.2.1

using this DQL:

Doctrine_Query::create()
->select('COUNT(s.status) as cn MIN(s.status) as minstat')
->from('LogisticOrder o')
->innerJoin('o.Status os')
->innerJoin('o.PickingRequests r')
->innerJoin('r.Status s')
->where('os.status=?', OrderStatusLog::$STATUS_PICKING)
->groupBy('r.order_id')
->having('minstat=? AND cn=1', array(512))
->getSqlQuery();

I get

SELECT COUNT(s4.status) AS s4__0 FROM sd_logisticorder s INNER JOIN sd_order_status_log s2 ON s.status_id = s2.id INNER JOIN sd_picking_request s3 ON s.id = s3.order_id INNER JOIN sd_picking_request_status s4 ON s3.id = s4.request_id WHERE (s2.status = ?) GROUP BY s3.order_id HAVING (minstat=? AND cn=1 )

Comment by Timo Haberkern [ 08/Jan/10 ]

Just to inform you: The problem is the missing space at the having operators

Doesn't work:
->having('minstat=? AND cn=1', array(512))

Works:
->having('minstat = ? AND cn = 1', array(512))





[DC-207] Masked exception makes it very difficult to debug Created: 10/Nov/09  Updated: 10/Nov/09  Resolved: 10/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.0-ALPHA1, 1.2.0-ALPHA2, 1.2.0-ALPHA3, 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Major
Reporter: Fabien Potencier Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

When you try to save an object, but the database does not exist, Doctrine throws a Doctrine_Transaction_Exception exception with the message "Rollback failed. There is no active transaction.".

But the real problem is that the database does not exit. The problem is in the Doctrine_Connection_UnitOfWork class around line 146:

        } catch (Exception $e) {
            // Make sure we roll back our internal transaction
            //$record->state($state);
            $conn->rollback();
            throw $e;
        }

The exception occurs because of "$conn->rollback();", and so the "throw $e;" is never reached.

We should probably throws an exception earlier about the fact that the database does not exist.






[DC-213] Doctrine_Import_Schema::parseSchema(): handling of global options in schema definition Created: 11/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Schema Files
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Raphael Schumacher Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

(independent from specific env)



 Description   

Doctrine allows schema files (schema.yml in my case as symfony user) to define global settings that shall be valid for each class (within the same schema file) to be taken as default unless specified otherwise within the class.
However, once an individual class does specify (even only) one single option, none of the global options are being used anymore at all. This is the current implementation as of in Doctrine_Import_Schema::parseSchema(), line 330.
IMHO this implementation makes the feature of rather little benefit for users, particularly because 'options' is an array, even a nested one since symfony 1.3 did introduce their own options therein ('forms' and 'filters').

Following example:

schema.yml
# global settings, as default for all classes
detect_relations:                   false
options:
    type:                           innodb
    collate:                        utf8_unicode_ci
    charset:                        utf8
    symfony:
        form:                       true
        filter:                     true

DocumentSource:
    tableName:                      dk_doc_source
    abstract:                       'Possible sources for documents (code set)'
    options:
        symfony:                    { filter: false }
    actAs:
        Timestampable:              ~
    columns:
        name:                       { type: string(63), notnull: true }
        description:                { type: string(255) }

DocumentType:
    tableName:                      dk_doc_type
    abstract:                       'Allowed types for documents'
    options:
        symfony:                    { form: false, filter: false }
    actAs:
        Timestampable:              ~
    columns:
        name:                       { type: string(63), notnull: true }
        description:                { type: string(255) }

DocumentTag:
    tableName:                      dk_doc_tag
    abstract:                       'Tags for documents'
    actAs:
        Timestampable:              ~
    columns:
        name:                       { type: string(63), notnull: true }
        description:                { type: string(255) }

After an import with the current implementation, the classes end up having the following options:

  • DocumentSource:
        options:                             # taken from the specific class, no global setting was taken over
            symfony:                    { filter: false }
    
  • DocumentType:
        options:                            # taken from the specific class , again no global setting was taken over
            symfony:                    { form: false, filter: false }
    
  • DocumentTag:
    options:                            # taken from the globals
        type:                           innodb
        collate:                        utf8_unicode_ci
        charset:                        utf8
        symfony:
            form:                       true
            filter:                     true
    

As a developer I originally understood the feature in that DocumentSource and DocumentType would still get the global option settings like collate, charset etc without having to repeat them again and again.

  • Like e.g. for DocumentSource:
    options:                            # global and class specific options brought together
        type:                           innodb
        collate:                        utf8_unicode_ci
        charset:                        utf8
        symfony:
            form:                       true
            filter:                     false
    

--> is the effect of the current implementation is intentional?
I.e. I wish to raise the question: shall globals...

  1. only be applicable to an individual class if the latter doesn't specifiy any option at all? (principle of XOR), or
  2. complement the class' individual options, i.e. the developer defines the desired default options as globals, and specifies any difference from that in the individual class? (principle of inheritance).

IMHO as a user of Doctrine & Symfony, I cleary prefer the inheritance principle (2).

A thinkable solution is to use array_replace_recursive() or a similar function instead of a simple assignment:

Doctrine_Import_Schema::parseSchema(); lines 326 - 333
CURRENT:
        // Apply the globals to each table if it does not have a custom value set already
        foreach ($array as $className => $table) {
            foreach ($globals as $key => $value) {
                if ( !isset($array[$className][$key])) {
                    $array[$className][$key] = $value;
                }
            }
        }
PATCH:
        // Apply the globals to each table if it does not have a custom value set already
        foreach ($array as $className => $table) {
            foreach ($globals as $key => $value) {
                   $array[$className][$key] = array_replace_recursive($value, $array[$className][$key]);    // do inherit the global settings
            }
        }

I haven't yet tried out this patch nor even tested it, since anything first depends from a clarification on the common expectations from the feature of globals in schema files.

Cheers, RAPHAEL

PS. update: I created a corresponding issue in Symfony trac.






[DC-204] [patch] Cloning or copying a query object keeps a reference to the previous hydrator Created: 09/Nov/09  Updated: 10/Nov/09  Resolved: 10/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Major
Reporter: Ariel Arjona Assignee: Guilherme Blanco
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File query_clone.patch    

 Description   

Upon cloning or copying a query object, the hydrator property still points to the original query. Changing it in the child object changes it for the parent object.

thanks to gnat42 for the patch






[DC-199] Combination of Searchable and I18n behaviors Created: 08/Nov/09  Updated: 18/Nov/09  Resolved: 18/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Behaviors
Affects Version/s: 1.2.0-BETA1
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Ilya Sabelnikov Assignee: Jonathan H. Wage
Resolution: Can't Fix Votes: 1
Labels: None
Environment:

Fedora 10, php 5.2.8, nginx, symfony 1.3-beta1



 Description   


I know, Doctrine allows to inherit behaviors. In my schema.yml i have added Searchable behavior to an I18n behavior.

schema.yml
Screencast:
  tableName: screencast
  actAs:
    Timestampable: ~
    I18n:
      fields:
        - title
        - is_sub_visible
      actAs:
        Searchable:
          fields: [title]
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
      unsigned: true
    slug: { type: string(127), notnull: true }
    is_visible: boolean(false)
    title: string(255)
    is_sub_visible: boolean(false)
  indexes:
    is_visible: { fields: [is_visible] }
    slug: { fields: [slug], type: unique }



By calling "Doctrine_Table::search" without defining second parameter (custom Doctrine_Query) works fine.
Then, when i pass the second paramter (by calling $q->execute() i got this exception:


Doctrine_Hydrator_Exception: Couldn't hydrate. Found non-unique key mapping named 'lang'. in /usr/lib/symfony/1.3-svn/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Hydrator/Graph.php on line 156

Hire is my test example "test.php"

test.php
<?php

// initializing Screencast and ScreencastTranslation tables
// in other case, will be thrown Doctrine_Exception with message "Couldn't find class ScreencastTranslation"
ScreencastTable::getTable();


$i18nTable = Doctrine::getTable('ScreencastTranslation');

// create query instance and add filter by "is_sub_visible = true" column
$q = $i18nTable->createQuery('st')->addWhere('st.is_sub_visible = ?', true);

// run search query
$q = $i18nTable->search('doctrine', $q);

// prints:
// FROM ScreencastTranslation st WHERE st.is_sub_visible = ? AND st.id IN (SQL:SELECT id FROM screencast_translation_index WHERE keyword = ? GROUP BY id)
print $q->getDql();

$doctrineCollection = $q->execute(); // on this line throws Doctrine_Hydrator_Exception

?>


 Comments   
Comment by Jonathan H. Wage [ 18/Nov/09 ]

Sorry this is a known issue with the behaviors and it is a bigger problem that can't be fixed. Some behaviors just won't work together.





[DC-202] Alias in InnerJoin-Update-Queries wrong Created: 09/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.0.13
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Timo Haberkern Assignee: Guilherme Blanco
Resolution: Can't Fix Votes: 0
Labels: None
Environment:

Windows, Symfony 1.2.9



 Description   

I tried to do an UPDATE-Operation like the following example:

$query = Doctrine_Query::create()
->update('PickingRequestStatus s')
->innerJoin('s.Request r')
->innerJoin('r.WorkStatus ws')
->set('s.status=?', PickingRequestStatus::$STATUS_WORK_CANCELLED)
->where('s.status = ?', array(PickingRequestStatus::$STATUS_WORK_STARTED))
->andWhere('ws.last_action_at < ?', $threshold);

The created SQL-Statement is wrong:
UPDATE sd_picking_request_status INNER JOIN sd_picking_request s2 ON s.request_id = s2.id INNER JOIN sd_picking_request_work_status s3 ON s2.id = s3.request_id SET status = 16 WHERE status = 8 AND last_action_at < '2009-11-08 11:00'

and you will get the following error-message: SQLSTATE[42S22]: Column not found: 1054 Unknown column 's.request_id' in 'on clause'

If you remove the s. in the JOIN-Statement everthing is fine:

UPDATE sd_picking_request_status INNER JOIN sd_picking_request s2 ON request_id = s2.id INNER JOIN sd_picking_request_work_status s3 ON s2.id = s3.request_id SET status = 16 WHERE status = 8 AND last_action_at < '2009-11-09 11:00'



 Comments   
Comment by Jonathan H. Wage [ 16/Nov/09 ]

This is one unfortunate limitation/issue with DELETE/UPDATE dql queries. You cannot perform any joins or anything. This works properly in Doctrine 2 though.





[DC-201] [PATCH] Level is oracle keyword (reopened #479) Created: 08/Nov/09  Updated: 10/Nov/09  Resolved: 10/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Nested Set
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Improvement Priority: Major
Reporter: Miloslav "adrive" Kmet Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File Level.patch    

 Description   

I created this ticket in connection to the http://trac.doctrine-project.org/ticket/479

The resolution was that it's fixed in http://trac.doctrine-project.org/changeset/3183/ - but it seems that it is fixed only in the changelog.

The LEVEL is an oracle keyword and the only way to use the NestedSet with Oracle is enabled quote identifiers.
We used this for about a year or more, but it is not so comfortable and this is the only reason why we are quoting identifiers.

But we started to use Oracle's spatial features and I was surprised that some oracle spatial functions are not able to work on quoted objects, and I started to use synonyms and extra columns with triggers as workaround. But it is so annoying and the patch is so simple



 Comments   
Comment by Jonathan H. Wage [ 10/Nov/09 ]

Thanks for the ticket and patch.





[DC-198] refreshRelated inserts records when One-to-One relationships are used and a related record is deleted Created: 08/Nov/09  Updated: 19/Nov/09  Resolved: 19/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.1.5
Fix Version/s: 1.2.0-RC1

Type: Bug Priority: Major
Reporter: Mario Bittencourt Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Mac OS X, PHP 5.2.11, MySQL 5.1.37


Attachments: File DC198TestCase.php    

 Description   

When one-to-one relationship is used and a refreshRelated is performed after a delete a new record is inserted with NULL values.

schema.yml

Email:
columns:
user_id: integer
address: string(150)
relations:
User:
local: user_id
foreign: id
type: one
foreignType: one
foreignAlias: email

User:
columns:
name: string(150)

Sample code

Create.php - create the user/email

$u = new User();
$u->name = 'Test';
$u->email->address = 'foo@bar.com';
$u->save();

Delete.php - remove the email

$u = Doctrine_Query::create()>from('User')>fetchOne();
$u->name = 'Test2' ;
$u->email->delete();
$u->refreshRelated('email');
$u->save();

The profile (of Delete.php)

connect 0.005211

query 0.000493
SELECT u.id AS u_id, u.name AS u_name FROM user u
prepare 0.000028
SELECT e.id AS e_id, e.user_id AS euser_id, e.address AS e_address FROM email e WHERE e.user_id = ?
execute 0.001086
SELECT e.id AS e_id, e.user_id AS euser_id, e.address AS e_address FROM email e WHERE e.user_id = ?
Array
(
[0] => 1
)
Total time: 0.00681829452515
fetch 0.000024
SELECT e.id AS e_id, e.user_id AS euser_id, e.address AS e_address FROM email e WHERE e.user_id = ?
fetch 0.000016
SELECT e.id AS e_id, e.user_id AS euser_id, e.address AS e_address FROM email e WHERE e.user_id = ?
begin 0.000147

prepare 0.000019
DELETE FROM email WHERE id = ?
execute 0.000253
DELETE FROM email WHERE id = ?
Array
(
[0] => 1
)
Total time: 0.00727772712708
commit 0.001120

prepare 0.000021
SELECT e.id AS e_id, e.user_id AS euser_id, e.address AS e_address FROM email e WHERE e.user_id = ?
execute 0.000333
SELECT e.id AS e_id, e.user_id AS euser_id, e.address AS e_address FROM email e WHERE e.user_id = ?
Array
(
[0] => 1
)
Total time: 0.0087513923645
fetch 0.000017
SELECT e.id AS e_id, e.user_id AS euser_id, e.address AS e_address FROM email e WHERE e.user_id = ?
begin 0.000104

prepare 0.000020
UPDATE user SET name = ? WHERE id = ?
execute 0.000291
UPDATE user SET name = ? WHERE id = ?
Array
(
[0] => Test2
[1] => 1
)
Total time: 0.00918316841125
prepare 0.000021
INSERT INTO email (id, user_id, address) VALUES (?, ?, ?)
execute 0.000193
INSERT INTO email (id, user_id, address) VALUES (?, ?, ?)
Array
(
[0] =>
[1] =>
[2] =>
)
Total time: 0.00939726829529
commit 0.000823

a var_dump of $u->toArray() after refreshRelated shows

array(3) {
["id"]=>
string(1) "1"
["name"]=>
string(7) "Test2"
["email"]=>
array(3)

{ ["id"]=> string(1) "1" ["user_id"]=> string(1) "1" ["address"]=> string(8) "foo@bar.com" }

}

And in the database I have null values for the email record.

This does not happen if I change the relationship to hasMany



 Comments   
Comment by Jonathan H. Wage [ 10/Nov/09 ]

This should be fixed in 1.2 now. Can you test 1.2?

Comment by Mario Bittencourt [ 11/Nov/09 ]

Sorry. At least in my tests this is still not solved.

After I delete and call refreshRelated the object still contains the old values and if I do a save it adds a new item with NULL values to the related table.

My code

$f = Doctrine_Query::create()>from('User')>fetchOne();
$f->name = 'Test2' ;
$f->email->delete();
$f->refreshRelated('email');
var_dump($f->toArray()); // first var_dump

$f->save();

var_dump($f->toArray()); // second var_dump

// first var_dump
array(3) {
["id"]=>
string(1) "1"
["name"]=>
string(7) "Test2"
["email"]=>
array(3)

{ ["id"]=> string(1) "1" ["user_id"]=> string(1) "1" ["address"]=> string(8) "foo@bar.com" }

}

// second var_dump
array(3) {
["id"]=>
string(1) "1"
["name"]=>
string(7) "Test2"
["email"]=>
array(3)

{ ["id"]=> string(1) "2" ["user_id"]=> string(1) "1" ["address"]=> string(8) "foo@bar.com" }

}

In the database the email table contains

id = 2
user_id = NULL
address = NULL

Comment by Jonathan H. Wage [ 12/Nov/09 ]

When I test the code you're providing, against 1.2. I don't get the results you explain. Can you make a Doctrine test case to show the problem? Because I can't seem to reproduce it after my changes to fix the issue.

Comment by Mario Bittencourt [ 15/Nov/09 ]

Hi,
Sure I can make a test case as soon as I find out how to do that.

Any urls of how to create a test case?

Comment by Jonathan H. Wage [ 16/Nov/09 ]

In the documentation: http://www.doctrine-project.org/documentation/manual/1_2/en/unit-testing

Comment by Jonathan H. Wage [ 18/Nov/09 ]

Any update on this? I am still trying to produce the problem but everything is working for me in my tests. I want to get this fixed in RC1 by this friday if a issue really exists.

Comment by Mario Bittencourt [ 18/Nov/09 ]

Hi Jon,

I'll be able to take another look today (at night) so I'd probably will have an update by tomorrow.

Regards.

Comment by Jonathan H. Wage [ 18/Nov/09 ]

Any update? Can we chat in IRC or something to help try and find the problem?

Comment by Mario Bittencourt [ 19/Nov/09 ]

Hi,

I've attached the test file you've requested. I hope this helps.

Tested: 419 test cases.
Successes: 4333 passes.
Failures: 2 fails.
Number of new Failures: 0

Doctrine_Ticket_DC198_TestCase..................................................failed

Doctrine_Ticket_DC198_TestCase : method testRemoveEmail failed on line 32
Value1: 0
!=
Value2: 3

Doctrine_Ticket_DC198_TestCase : method testRemoveEmail failed on line 36

Comment by Jonathan H. Wage [ 19/Nov/09 ]

Thanks. As soon as I ran the test case I saw the problem and could fix it much much faster Thanks a lot!!





[DC-197] [patch] default model orderBy option breaks data-load task Created: 06/Nov/09  Updated: 10/Nov/09  Resolved: 10/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Major
Reporter: Ariel Arjona Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File doctrine12_orderby_select.patch    

 Description   

currently the default orderBy clause one can specify for models gets added to all queries, including DELETE and UPDATE.
This breaks data-load because it includes in the orderBy the table alias but currently only SELECT queries support aliases.

For example if I have the following schema:

Mytable:
options:

{ orderBy: name ASC }

columns:
name:

{ type: string(100), notnull: true }

The data-load task does a Doctrine::getTable('Mytable')>delete()>execute(); to clear the table before loading the fixtures which results in the following SQL:
DELETE FROM mytable ORDER BY m.name ASC

which errors out as the m alias was not defined.

Attached is the patch that makes only SELECT queries get the default orderBy clause from the option.






[DC-194] Oracle dropDatabase does not work Created: 06/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.1.4, 1.1.5
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Igor D'Astolfo Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Oracle 10 or higher



 Description   

Doctrine_Export_Oracle::dropDatabase does not work, it contains some SQL errors. Here is the patch:

--- Doctrine-1.1.5/lib/Doctrine/Export/Oracle.php	2009-11-03 19:33:04.000000000 +0100
+++ doctrine/Doctrine/Export/Oracle.php	2009-11-06 14:40:46.000000000 +0100
@@ -76,17 +76,19 @@
         $sql[] = "BEGIN
 FOR I IN (select table_name from user_tables)
 LOOP 
-EXECUTE IMMEDIATE 'DROP TABLE '||I.table_name||' CASCADE CONSTRAINTS';
+EXECUTE IMMEDIATE 'DROP TABLE \"'||I.table_name||'\" CASCADE CONSTRAINTS';
 END LOOP;
 END;";
 
         $sql[] = "BEGIN
 FOR I IN (SELECT SEQUENCE_NAME, SEQUENCE_OWNER FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER <> 'SYS')
 LOOP 
-EXECUTE IMMEDIATE 'DROP SEQUENCE '||I.SEQUENCE_OWNER||'.'||I.SEQUENCE_NAME;
+EXECUTE IMMEDIATE 'DROP SEQUENCE \"'||I.SEQUENCE_OWNER||'\".\"'||I.SEQUENCE_NAME||'\"';
 END LOOP;
 END;";





[DC-191] Doctrine_Migration->loadMigrationClassesFromDirectory fail when launched 2 times Created: 05/Nov/09  Updated: 10/Nov/09  Resolved: 10/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Migrations
Affects Version/s: 1.2.0-ALPHA2
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Major
Reporter: thibault duplessis Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

daily symfony 1.3 svn



 Description   

When I need to create a Doctrine_Migration twice during a same php processus, the migrations version numbers get wrong.

In Doctrine_Migration->loadMigrationClassesFromDirectory method, I see :

        if (isset(self::$_migrationClassesForDirectories[$directory])) {
            $migrationClasses = (array) self::$_migrationClassesForDirectories[$directory];
            $this->_migrationClasses = array_merge($migrationClasses, $this->_migrationClasses);
        }

The problem is that array_merge loose the array keys. In the $this->_migrationClasses context, array keys are very important because they are the version numbers.

So when if (isset(self::$_migrationClassesForDirectories[$directory])) is true ( ie the second time we use the Doctrine_Migration classs ) all the migrations versions get wrong.

I hope my description is clear enough.



 Comments   
Comment by Jonathan H. Wage [ 10/Nov/09 ]

After looking at it, that code didn't make sense and it could never work, you are right. I removed it. Now if you call that function twice it will reset everything and reload the classes from the configured directories.





[DC-192] Doctrine_Import_Builder Missing Relation Alias When Using classPrefix Created: 05/Nov/09  Updated: 10/Nov/09  Resolved: 10/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Major
Reporter: Jacky Nguyen Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PHP 5.2.x, Windows (All)



 Description   

Doctrine_Import_Builder, line 383

$alias = (isset($relation['alias']) && $relation['alias'] !== $relation['class']) ? ' as ' . $relation['alias'] : '';

For example, if both class name and alias is "User" and we make use of classPrefix (i.e "Model_"), the generated class name will actually be "Model_User". The comparison of:

$relation['alias'] !== $relation['class']

does not cover the prefix, which lead to the missing of alias when generating models, i.e

$this->hasOne('Model_User', ...

instead of

$this->hasOne('Model_User as User', ...

Suggested fix:

$alias = (isset($relation['alias']) && $relation['alias'] !== $this->_classPrefix . $relation['class']) ? ' as ' . $relation['alias'] : '';






[DC-190] Fatal error while connecting after an reset of the Doctrine_Manager Created: 04/Nov/09  Updated: 10/Nov/09  Resolved: 10/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Attributes
Affects Version/s: 1.2.0-ALPHA3, 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Major
Reporter: Bas K Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

osx10.6.1, php5.3.0



 Description   

Doctrine_Manager::connection('sqlite::memory:');
Doctrine_Manager::resetInstance();
Doctrine_Manager::connection('sqlite::memory:');
Fatal error: Call to a member function onOpen() on a non-object in ...../Doctrine/Connection.php on line 221

which is $this->getAttribute(Doctrine_Core::ATTR_LISTENER)->onOpen($this);

The Doctrine_Core::ATTR_LISTENER attribute is not set in the connection nore in the manager... This is because Doctrine_Manager::resetInstance does remove all attributes but Doctrine_Manager::setDefaultAttributes does not allow to set the default attributes twice.

This method can only run once, because it use a local static $init variable and since Doctrine_Manager is a Singleton the init value should stored within the instance.

What happens :
1. In Doctrine_Manager::setDefaultAttributes() the Doctrine_Core::ATTR_LISTENER is set to new Doctrine_EventListener().
2. A connection get its attributes from the manager when not available in the connection.
3. When Doctrine_Manager::reset() is called the attributes are gone and should be set again...
4. However because the Doctrine_Manager::setDefaultAttibutes method only can run once (a check is set in a static local boolean) the listener is not recreated and thus subsequent connections will fatally fail

patch by
A fix is simple and I have it running locally...

1. add an private $_inited or $_defaultAttributesSet property to Doctrine_Manager, defaults to false;
2. on Doctrine_Manager::reset reset it to its default (false)
3. on Doctrine_Manager::setDefaultAttibutes do nothing when the property equals true, but when the property is false proceed with setting the default attributes...






[DC-187] The Unique does not work correctly when using "SoftDelete" Created: 04/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Behaviors
Affects Version/s: 1.1.4, 1.1.5
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Fabian Brussa Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

WindowsXP, WAMP 2.0



 Description   

Scenario:

class User extends Doctrine_Record
{
public function setTableDefinition()

{ $this->hasColumn('username', 'string', 255); $this->hasColumn('email', 'string', 255); $this->unique('username', 'email'); }

public function setUp()

{ $this->actAs('SoftDelete'); }

}

Test:

//create User
$user = new User();
$user->username = 'Fabian';
$user->email = 'fabian@test.com';
$user->save();

...
...
// delete user
$user = Doctrine_Query::create()
->select('*')
->from('User')
->where("id=1")
->fetchOne();
$user->delete(); //this mark as deleted the user (delete_at field)

....
....

//create User with same data
$user = new User();
$user->username = 'Fabian';
$user->email = 'fabian@test.com';
$user->save();

// This throw error by the "unique"



 Comments   
Comment by Jonathan H. Wage [ 10/Nov/09 ]

I think you should add deleted_at to the array of fields to be unique by.

Comment by Fabian Brussa [ 10/Nov/09 ]

Jonathan, but deleted_at is null, therefore can not be part of the array of fields .

I tried adding it does not work, take all the data as different

Comment by Jonathan H. Wage [ 10/Nov/09 ]

I see. If that is the case, I don't see of any way to resolve this. Do you?

Comment by Fabian Brussa [ 10/Nov/09 ]

mmm, if it is possible to know whether the class acts as SoftDelete at the time of validating the unique, could skip if is marked as deleted (deleted_at not null)

Comment by Jonathan H. Wage [ 10/Nov/09 ]

It is not Doctrine, it is the database that throws the error due to the unique index.

Comment by Fabian Brussa [ 11/Nov/09 ]

Jonathan, in the database is not created the unique index, only in definition of the class users with ($this->unique('username', 'email'); )

I'm seeing if is possible to consider the "deleted_at" in then Validate Method in Doctrine_Validator_Unique

Comment by Fabian Brussa [ 11/Nov/09 ]

Adding these lines in the method "validate", class "Doctrine_Validator_Unique", just before a

$stmt  = $table->getConnection()->getDbh()->prepare($sql);

works fine
.

 
$arr = $table->getTemplates();
if ( array_key_exists("Doctrine_Template_SoftDelete",$arr))
{
	$fieldNameDeleteAt = $arr["Doctrine_Template_SoftDelete"]->getOption("name"); 
	$sql .= " AND $fieldNameDeleteAt IS NULL";
}

Be okay to do this here?

Prerequisite: not defined unique index in the database.

Comment by Jonathan H. Wage [ 11/Nov/09 ]

I am not sure, because the unique index is always created in the database. Can you even disable it? So adding this code is useless since the index is created by default and will throw the exception.

Comment by Jonathan H. Wage [ 11/Nov/09 ]

This code:

$this->unique('username', 'email');

Does two things, it adds a unique validator for the columns, but it also adds a unique index in the mapping information which gets created in the database if it supports unique indexes.

Comment by Fabian Brussa [ 11/Nov/09 ]

Hi Jonathan,

Thanks for your swift response!

I understand that the indexes are created automatically in the database and that is what I think should (or could) work differently.

When creating an index for multiple fields in combination with the softdelete I would like to propose to not create the indexes in the database and depend on the doctrine Unique class to handle this. In this case the doctrine Unique class should take into account that softdelete is activated and thus only query the not deleted records to check if they are unique.

I hope you see this as a solution for a common problem and are willing to take it into consideration.

Comment by Jonathan H. Wage [ 12/Nov/09 ]

I would rather not implement specific hacks for individual behaviors. Instead I think we need more generic solutions.

To get around this you can do the following now:

        $this->unique(
            array('username', 'email'),
            array('where' => "deleted_at IS NULL"),
            false
        );

The 2nd argument is an array of options for the unique validator. It already accepted a "where" key so you can add deleted_at IS NULL to the where condition. The 3rd argument "false" is so that it does not create the unique index in the database.





[DC-186] Patch to correct CLI tests Created: 04/Nov/09  Updated: 04/Nov/09  Resolved: 04/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Cli
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Improvement Priority: Major
Reporter: Dan Bettles Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PHP 5.3, Darwin, Macbook


Attachments: File Cli_testcase_corrections.diff    

 Description   

Enclosed is a little patch to correct my CLI tests.

The patch wraps test runs on the CLI in an output buffer to prevent output to the console when the unit tests are run. This output from the CLI could be mistaken for errors, but it's expected and only looks unfriendly - no errors / exceptions are thrown.






[DC-181] Exception thrown - nested query in count query Created: 04/Nov/09  Updated: 05/Nov/09  Resolved: 04/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: None
Fix Version/s: 1.0.14

Type: Bug Priority: Major
Reporter: Mishal Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
Reference
relates to DC-77 Query-Parameters are not correctly Re... Closed

 Description   

My model is:

product: [ id, name]
product_category_ref [product_id, category_id]
product_category: [id, name]

I have a query like this:
$page = 1;
$ids = array(1,2);
$query = Doctrine_Query::create()
->from('Product p')
->innerJoin('p.Categories cat')
->andWhere('p.is_active = 1')
->andWhereIn('p.id', $ids);

$pager = new Doctrine_Pager($query, $page, sfConfig::get('app_eshop_pager_limit', 5));

$pager->execute(array(), Doctrine::HYDRATE_ARRAY);

throws and exception: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

Stack trace:

  • at ()
    in SF_ROOT_DIR\plugins\sfDoctrinePlugin\lib\doctrine\Doctrine\Connection.php line 1086 ...
    1083.
    1084. $name = 'Doctrine_Connection_' . $this->driverName . '_Exception';
    1085.
    1086. $exc = new $name($e->getMessage(), (int) $e->getCode());
    1087. if ( ! isset($e->errorInfo) || ! is_array($e->errorInfo)) { 1088. $e->errorInfo = array(null, null, null, null); 1089. }
  • at Doctrine_Connection->rethrowException(object('PDOException'), object('Doctrine_Connection_Statement'))
    in SF_ROOT_DIR\plugins\sfDoctrinePlugin\lib\doctrine\Doctrine\Connection\Statement.php line 253 ...
    250. } catch (Doctrine_Adapter_Exception $e) { 251. }

    252.
    253. $this->_conn->rethrowException($e, $this);
    254.
    255. return false;
    256. }

  • at Doctrine_Connection_Statement->execute(array('1', '2', '1', '2'))
    in SF_ROOT_DIR\plugins\sfDoctrinePlugin\lib\doctrine\Doctrine\Connection.php line 1014 ...

I found a place in Doctrine/Query.php (line 1155), changed line:

$list = $this->_conn->execute($subquery, $this->getParams($params))->fetchAll(Doctrine::FETCH_COLUMN);

to

$list = $this->_conn->execute($subquery, $params)->fetchAll(Doctrine::FETCH_COLUMN);

and it works ok, im not sure if that brokes anything



 Comments   
Comment by Jonathan H. Wage [ 04/Nov/09 ]

This is the ticket and fix that caused this issue.

Comment by Jonathan H. Wage [ 04/Nov/09 ]

Can you test this change? it should be better now.

Comment by Mishal [ 05/Nov/09 ]

It works! Thanks!





[DC-182] 1.0.13 limit() broke with : Created: 04/Nov/09  Updated: 01/Dec/09  Resolved: 01/Dec/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.0.13
Fix Version/s: 1.0.14

Type: Bug Priority: Major
Reporter: fred Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

osx, symfony 1.2.9



 Description   

$q = Doctrine_Query::create()
->from('news n')
->leftJoin('n.Translation t')
->Where('n.published = ?', 1)
->limit(10)
->orderBy('n.id DESC');

('SELECT DISTINCT n3.id FROM news n3 LEFT JOIN news_translation n4 ON n3.id = n4.id WHERE n3.published = ? ORDER BY n3.id DESC LIMIT 10', array(1, 1))

The issue is just the transformation from '1' to array...

symfony 1.2.9 with doctrine VERSION = '1.0.13';

The limit seem to be broken.

SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

I'll submit test case ASAP.



 Comments   
Comment by Jonathan H. Wage [ 04/Nov/09 ]

Can you test this against the latest 1.0 branch in SVN? Thanks

Comment by fred [ 09/Nov/09 ]

Work for me. Thanks for the excellent support.

Comment by Alex Fernandez [ 26/Nov/09 ]

I just updated to latest from 1.0 branch and I still see a problem. Before it was an issue with the params array content being duplicated. Now there isn't any parameters being retrieved. Here's part of the exception output. Let me know if you need any additional info. BTW, I'm using sf 1.2 branch. Was using Doctrine 1.0.13. Now using latest from svn 1.0 branch.

<name>Doctrine_Connection_Mysql_Exception</name>

<message>
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? LIMIT 5' at line 1
</message>

<traces>

<trace>
at () in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection.php line 1086
</trace>

<trace>
at Doctrine_Connection->rethrowException(object('PDOException'), object('Doctrine_Connection_Mysql')) in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection.php line 1034
</trace>

<trace>
at Doctrine_Connection->execute('SELECT DISTINCT j5.id FROM jobeet_job j5 LEFT JOIN jobeet_category j6 ON j5.category_id = j6.id LEFT JOIN jobeet_category_affiliate j8 ON (j6.id = j8.category_id) LEFT JOIN jobeet_affiliate j7 ON j7.id = j8.affiliate_id WHERE j7.id = ? LIMIT 5', array()) in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query.php line 1155
</trace>

<trace>
at Doctrine_Query->getSqlQuery(array()) in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query/Abstract.php line 1751
</trace>

<trace>
at Doctrine_Query_Abstract->getSql() in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query/Abstract.php line 822
</trace>

<trace>
at Doctrine_Query_Abstract->getRootAlias() in SF_ROOT_DIR/lib/model/doctrine/JobeetJobTable.class.php line 41
</trace>

<trace>
at JobeetJobTable->addActiveJobsQuery(object('Doctrine_Query')) in SF_ROOT_DIR/lib/model/doctrine/JobeetAffiliate.class.php line 32
</trace>

<trace>
at JobeetAffiliate->getActiveJobs('5') in SF_ROOT_DIR/lib/model/doctrine/JobeetJobTable.class.php line 84
</trace>

<trace>
at JobeetJobTable->getForToken(array('token' => '52aaf00c06a0f34522ad857412f5c4590287432f', 'limit' => '5', 'sf_format' => 'xml')) in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/routing/sfDoctrineRoute.class.php line 122
</trace>

<trace>
at sfDoctrineRoute->getObjectsForParameters(array('module' => 'api', 'action' => 'list', 'token' => '52aaf00c06a0f34522ad857412f5c4590287432f', 'limit' => '5', 'sf_format' => 'xml')) in SF_SYMFONY_LIB_DIR/routing/sfObjectRoute.class.php line 141
</trace>

Comment by Alex Fernandez [ 26/Nov/09 ]

From the trace output and code, it looks like the call to getSQL on line 822 (Doctrine/Query/Abstract.php) is not even getting the $params array.

Comment by Alex Fernandez [ 26/Nov/09 ]

I changed line 822 in Abstract.php to the following:

$this->getSql($this->getParams());

Now all is fine. Not sure if this is the correct fix though.

Comment by Jonathan H. Wage [ 28/Nov/09 ]

Any chance someone can provide a test case for this?

Comment by Jonathan H. Wage [ 30/Nov/09 ]

I am still having issues reproducing this. Can someone help with reproducing it? Everything is working on my end as of right now. I'll give it another week or so before I close the ticket.

Comment by Alex Fernandez [ 30/Nov/09 ]

The way I happened to find this issue was during Day 16 of the Jobeet toturial. The last item for day 16 was telling the user to implement one of the requirements from Day 2:
"The affiliate can also limit the number of jobs to be returned, and refine his query by specifying a category."

So what I did was modify my route to take a limit like below:

  1. apps/frontend/config/routing.yml
    api_jobs:
    url: /api/:token/jobs.:sf_format/:limit
    class: sfDoctrineRoute
    param: { module: api, action: list, limit: 0 }

    options:

    { model: JobeetJob, type: list, method: getForToken }

    requirements:
    sf_format: (?:xml|json|yaml)

Then I modified the JobeetAffiliate.class.php file:

public function getActiveJobs($limit = 0)
{
$q = Doctrine_Query::create()
->select('j.*')
->from('JobeetJob j')
->leftJoin('j.JobeetCategory c')
->leftJoin('c.JobeetAffiliates a')
>where('a.id = ?', $this>getId());

if ($limit > 0)

{ $q = $q->limit($limit); }

$q = Doctrine::getTable('JobeetJob')->addActiveJobsQuery($q);

return $q->execute();
}

Then changed the JobeetJobTable.class.php class for the following method:

public function getForToken(array $parameters)
{
$affiliate = Doctrine::getTable('JobeetAffiliate') ->findOneByToken($parameters['token']);
if (!$affiliate || !$affiliate->getIsActive())

{ throw new sfError404Exception(sprintf('Affiliate with token "%s" does not exist or is not activated.', $parameters['token'])); }

return $affiliate->getActiveJobs((int) $parameters['limit']);
}

Requesting that route with any integer for limit would cause that error.

I have since moved on to restart the Jobeet tutorial with Symfony 1.4.

Comment by Jonathan H. Wage [ 01/Dec/09 ]

Can you give it a try with 1.0 now?

Comment by Jonathan H. Wage [ 01/Dec/09 ]

re-open if problem persists after my last change.

Comment by Alex Fernandez [ 01/Dec/09 ]

This worked. Thanks!





[DC-179] Wrong length estimation in Doctrine_Validator->validateLength() if locale sets decimal point other than "dot" Created: 04/Nov/09  Updated: 04/Nov/09  Resolved: 04/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Validators
Affects Version/s: 1.2.0-ALPHA1
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Major
Reporter: Adam Michalunio Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Apache/2.2.11 (Win32) PHP/5.2.11, windows vista


Attachments: File Validator.php    

 Description   

Test case:
1) set locale: setlocale(LC_ALL, "") (on windows it sets current international control panel settings), in case of Polish locale it changes decimal point to ',' (comma)
2) try to save value "12,12" of decimal type field (mysql type):

{ type: decimal(4), scale: 2 }

,
3) it gives you validation error (length)

Summary:
Doctrine_Validator->validateLength() could not count length properly.

Idea:
I changed dot character in explode function to proper env character:

// changes start
$localeInfo = localeconv();
$e = explode($localeInfo["mon_decimal_point"], $value);
// changes end

It works for me.

Enclosed Validator.php






[DC-180] [PATCH] Unique index name for column aggregation key column Created: 04/Nov/09  Updated: 04/Nov/09  Resolved: 04/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Record
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Major
Reporter: Miloslav "adrive" Kmet Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File RecordAbstract.php.patch    

 Description   

When using column aggregation colum with the same name on multiple models, and exporting schema to database, I have a collisions with names in Oracle (I think others are affected too).

{{
CREATE INDEX "type" ON "nt_organism_property" ("type")
CREATE INDEX "type" ON "nt_property" ("type")
CREATE INDEX "type" ON "st_node" ("type")
}}

I propose to prefix the index name with the table name






[DC-175] New hardDelete() on Soft Delete Template creates blank records Created: 03/Nov/09  Updated: 03/Nov/09  Resolved: 03/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Behaviors
Affects Version/s: 1.2.0-ALPHA3
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Major
Reporter: Ryan Weaver Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: File patch    

 Description   

When using the new hardDelete() in the SoftDelete template, the postDelete() listener is saving a blank record because it calls ->save() on the record, even if the record was hard deleted.

    public function postDelete(Doctrine_Event $event)
    {
      $event->getInvoker()->save();
    }

should be

 
    public function postDelete(Doctrine_Event $event)
    {
      if ( ! $this->_options['hardDelete']) {
        $event->getInvoker()->save();
      }
    }





[DC-178] Import Builder doesn't use default table class name Created: 04/Nov/09  Updated: 04/Nov/09  Resolved: 04/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export, Inheritance, Record
Affects Version/s: 1.2.0-ALPHA1, 1.2.0-ALPHA2, 1.2.0-ALPHA3, 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA2

Type: Bug Priority: Major
Reporter: Eugene Janusov Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File DC-178.patch    

 Description   

I use Symfony 1.2.9 with Doctrine 1.2 trunk.

I also make use of the new Doctrine's feature to specify custom table class. For that, in the config/ProjectConfiguration.class.php I have the following code:

   public function configureDoctrine(Doctrine_Manager $manager)
   {
      ...
      $manager->setAttribute(Doctrine::ATTR_TABLE_CLASS, 'Platform_DoctrineTable');
      ...
   }

And that works fine. But when I comment out this line and re-generate model classes, I get broken table class definitions like:

class AccountTable extends 
{

}

Notice the lack of base class name.

It seems the problem resides in Doctrine_Import_Builder's constructor:

    public function __construct()
    {
        $this->_baseTableClassName = Doctrine_Manager::getInstance()->getAttribute(Doctrine_Core::ATTR_TABLE_CLASS);
        $this->loadTemplate();
    }

So, the default value of $this->_baseTableClassName always overwrites by Doctrine_Core::ATTR_TABLE_CLASS attribute value.



 Comments   
Comment by Eugene Janusov [ 04/Nov/09 ]

Proposed patch attached.





[DC-171] make it possible to force deletion when using softdelete Created: 02/Nov/09  Updated: 03/Nov/09  Resolved: 03/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: None
Fix Version/s: 1.2.0-BETA1

Type: New Feature Priority: Major
Reporter: Lukas Kahwe Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

it would be nice to be able to force deleting when using softdelete. right now it seems like there is no way to still be able to do a real DELETE.
http://www.doctrine-project.org/documentation/manual/1_1/en/behaviors:core-behaviors:softdelete

something like $record->delete(true);

take for example some undo feature. there might be a point where i want to purge the possibility to do an undo (like at the end of the session).






[DC-172] change 6611 wrong Created: 02/Nov/09  Updated: 02/Nov/09  Resolved: 02/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: None
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Major
Reporter: Gordon Franke Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

i think the change has a logic error



 Description   

see line 95 in branches/1.2/lib/Doctrine/Connection/UnitOfWork.php

if ($ids) {
$record->unlinkInDb($alias, array());
} else if ($ids) {
$record->unlinkInDb($alias, array_keys($ids));
}



 Comments   
Comment by Jonathan H. Wage [ 02/Nov/09 ]

Thanks for catching that.





[DC-169] replace() method does not affect Timestampable fields Created: 02/Nov/09  Updated: 03/Nov/09  Resolved: 03/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Timestampable
Affects Version/s: 1.2.0-ALPHA3
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Major
Reporter: gregoire_m Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

LAMP, symfony 1.3.0-BETA1



 Description   

I have a Timestampable behavior on a table. If I create or edit an object of this table using the ->replace() method instead of ->save(), the Timestampable fields (created_at and updated_at by default) are not changed.






[DC-165] outdated symfony Yaml parser causes troubles Created: 31/Oct/09  Updated: 03/Nov/09  Resolved: 03/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: File Parser
Affects Version/s: 1.0.12, 1.1.4, 1.2.0-ALPHA1
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Major
Reporter: Fabian Lange Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

all doctrine versions use an imported and modified version of sfYaml.
Either that needs to be changed to an external, or bugfixes need to be ported.
see this ticket from symfony trac:
http://trac.symfony-project.org/ticket/7496

I wanted to use some yaml in a fixture to populate data for the "array"-Fieldtype.

In the fixture I used:

items:
  -
    name:           temp_zone_1
    fieldLabel:     Temp. Zone 1 [°C]
    value:          997
    minValue:       0
    maxValue:       3000
...

the resulting serialized array in the table array looked like:

s:5:"items";a:9:{i:0;a:5:{s:4:"name";s:11:"temp_zone_1";s:10:"fieldLabel";s:18:"Temp. Zone 1 [°C]";s:5:"value";s:3:"997";s:8:"minValue";i:0;s:8:"maxValue";s:4:"3000";}...

There you can easily see, that "value" is now a string, "minValue" an integer (why?) and maxValue another string. This went awfully wrong somewhere.

= Workaround and/or solution =
I took the current parser from `lib/yaml/sfYamlParser.php` and copied it into the existing Parser in `lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Parser/YamlSf/Parser.php`. That fixed the problem.

== Additional Information ==

used Version in Symfony 10832 2008-08-13
used Version in sfDoctrinePlugin 8869 2008-05-09

HTH,
Michael






[DC-163] Validator throws out a data type which the schema processing has accepted Created: 31/Oct/09  Updated: 03/Nov/09  Resolved: 03/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: None
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Major
Reporter: Colin Fine Assignee: Guilherme Blanco
Resolution: Fixed Votes: 0
Labels: None
Environment:

Fedora 10, symfony 1.2, postgresql 8.4.1. I have been unable to find any information as to which version of Doctrine I have: it came with symfony 1.2



 Description   

Doctrine accepts 'char' in the (yml) schema, and creates the database and model.
Then an attempt to save a record raises a Doctrine_Validator_Exception, which turns out to contain no validation message, but just the cryptic
[_errors:protected] => Array
(
[nickname] => Array
(
[0] => type
)

)

[_validators:protected] => Array
(
)

Only by looking at the source did I discover that what this means is that the validator does not accept the column type 'char' - because it's not hard-coded in Doctrine_Validator::isValidType.

I've vacillated over whether to classify this as 'Major' or Minor': once I've realised what's going on, it's easy to work round; but it is a show-stopper for a Doctrine novice.



 Comments   
Comment by Jonathan H. Wage [ 03/Nov/09 ]

This is already fixed in the Doctrine 1.2 branch which comes with symfony 1.3





[DC-159] No use of Offset in the Limit / Offset Documentation Created: 30/Oct/09  Updated: 30/Oct/09  Resolved: 30/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: Documentation
Affects Version/s: None
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Major
Reporter: Pascal Helfenstein Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

any



 Description   

There is no mentioning how to use the offset funktion in the "LIMIT and OFFSET clauses" chapter in the Doctrine 1.1 Documentation.

Some Example should feature:

->limit(12)
->offset(3)

to show how to use it.



 Comments   
Comment by Jonathan H. Wage [ 30/Oct/09 ]

Enhanced this for the 1.2 documentation since 1.1 end of life is approaching.

Comment by Pascal Helfenstein [ 30/Oct/09 ]

thanks





[DC-158] Postgresql Import does not recognize all parts of a composite primary key as primary keys Created: 29/Oct/09  Updated: 03/Nov/09  Resolved: 03/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.0.13
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Major
Reporter: Moritz Breit Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Doctrine 1.1 from current SVN with PostgreSQL 8.3.8


Attachments: Text File pgsql_import.patch    

 Description   

If a PostgreSQL table has a composite primary key, Doctrine import ("generate-models-db") will only mark the first column of the composite key as primary. This is due to a bug in Doctrine_Import_Pgsql.

I have attached a short patch against the current 1.1 branch (revision 6580). The version 1.2 seems to have the same problem.
I have tested the patch with PostgreSQL 8.3.8.



 Comments   
Comment by Moritz Breit [ 02/Nov/09 ]

Small test case for this bug:

Database schema:

schema.sql
CREATE TABLE testa (
  id bigint NOT NULL,
  CONSTRAINT testa_pkey PRIMARY KEY (id)
);

CREATE TABLE testb (
  id bigint NOT NULL,
  CONSTRAINT testb_pkey PRIMARY KEY (id)
);

CREATE TABLE testa_testb (
  testa bigint NOT NULL,
  testb bigint NOT NULL,
  CONSTRAINT testa_testb_pkey PRIMARY KEY (testa, testb),
  CONSTRAINT fktesta FOREIGN KEY (testa) REFERENCES testa (id),
  CONSTRAINT fktestb FOREIGN KEY (testb) REFERENCES testb (id)
);

This is a typical many-to-many relationship with a mapping table.
Note that testa_testb has a composite primary key with two columns, testa and testb.

Generated code before applying the patch (generateModelsFromDb):

BaseTestaTestb.php
abstract class BaseTestaTestb extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->setTableName('testa_testb');
        $this->hasColumn('testa', 'integer', 8, array(
             'type' => 'integer',
             'length' => 8,
             'unsigned' => false,
             'primary' => true,
             ));
        $this->hasColumn('testb', 'integer', 8, array(
             'type' => 'integer',
             'length' => 8,
             'unsigned' => false,
             'notnull' => true,
             'primary' => false, // This should be true
             ));
    }
...

Generated code after applying the patch:

BaseTestaTestb.php
abstract class BaseTestaTestb extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->setTableName('testa_testb');
        $this->hasColumn('testa', 'integer', 8, array(
             'type' => 'integer',
             'length' => 8,
             'unsigned' => false,
             'primary' => true,
             ));
        $this->hasColumn('testb', 'integer', 8, array(
             'type' => 'integer',
             'length' => 8,
             'unsigned' => false,
             'primary' => true,
             ));
    }
...




[DC-151] Doctrine_Collection::loadRelated() issues with empty collection and handling with no name parameter Created: 28/Oct/09  Updated: 30/Oct/09  Resolved: 30/Oct/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.0-ALPHA3
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: Major
Reporter: Lukas Kahwe Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File Collection.php.patch    

 Description   

When no name is passed, the list variable isnt passed to the where() method call. Also in all cases an empty $list variable isnt handled properly.






[DC-153] Some pieces of Doctrine's internal code can't work properly without a default connection Created: 28/Oct/09  Updated: 03/Nov/09  Resolved: 03/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.1.4, 1.2.0-ALPHA1, 1.2.0-ALPHA2, 1.2.0-ALPHA3
Fix Version/s: 1.2.0-BETA1

Type: Bug Priority: