[DC-1035] ORA-01791 due to bad driver name in Doctrine_Adapter_Oracle Created: 01/Sep/11  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Blocker
Reporter: Jayson LE PAPE Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Windows 7 64 bits, PHP 5.2.11, Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi, Symfony 1.4.13



 Description   

When i execute this code:

 
$q = Doctrine_Query::create()
            ->from('AGENT ag')
            ->leftJoin('ag.CHANTIER_AGENT cag)
            ->orderBy('ag.nom')
            ->limit(10)
            ->execute();
$q2 = Doctrine_Query::create()
            ->from('AGENT ag')
            ->leftJoin('ag.CHANTIER_AGENT cag)
            ->orderBy('ag.nom')
            ->limit(10)
            ->execute();

Doctrine executes :

 
SELECT a.pk AS a__pk, a.ts AS a__ts, a.ck_agent AS a__ck_agent, a.matricule AS a__matricule, a.nom AS a__nom, 
a.prenom AS a__prenom, a.agent_maitrise AS a__agent_maitrise, c.pk AS c__pk, c.ts AS c__ts, c.ck_chantier_agent AS c__ck_chantier_agent, 
c.ek_chantier AS c__ek_chantier, c.fk_chantier AS c__fk_chantier, c.ek_agent AS c__ek_agent, c.fk_agent AS c__fk_agent 
FROM AGENT a 
LEFT JOIN CHANTIER_AGENT c ON a.ck_agent = c.ek_agent 
WHERE a.ck_agent IN (
SELECT a2.ck_agent FROM ( 
SELECT DISTINCT a2.ck_agent, a2.nom FROM AGENT a2 LEFT JOIN CHANTIER_AGENT c2 ON a2.ck_agent = c2.ek_agent ORDER BY a2.nom ) 
a2 WHERE ROWNUM <= 10) ORDER BY a.nom

SELECT a.pk AS a__pk, a.ts AS a__ts, a.ck_agent AS a__ck_agent, a.matricule AS a__matricule, a.nom AS a__nom, 
a.prenom AS a__prenom, a.agent_maitrise AS a__agent_maitrise, c.pk AS c__pk, c.ts AS c__ts, c.ck_chantier_agent AS c__ck_chantier_agent, 
c.ek_chantier AS c__ek_chantier, c.fk_chantier AS c__fk_chantier, c.ek_agent AS c__ek_agent, c.fk_agent AS c__fk_agent 
FROM AGENT a 
LEFT JOIN CHANTIER_AGENT c ON a.ck_agent = c.ek_agent 
WHERE a.ck_agent IN (
SELECT a2.ck_agent FROM ( 
SELECT DISTINCT a2.ck_agent FROM AGENT a2 LEFT JOIN CHANTIER_AGENT c2 ON a2.ck_agent = c2.ek_agent ORDER BY a2.nom ) 
a2 WHERE ROWNUM <= 10) ORDER BY a.nom

This causes "Oracle DB Error ORA-01791 not a SELECTed expression" because the sql query don't have a2.nom in SELECT DISTINCT and it's indispensable for ORDER BY a2.nom
The problem is caused by the variable $attributes in Doctrine_Adapter_Oracle :

 
protected $attributes = array(Doctrine_Core::ATTR_DRIVER_NAME    => "oci8",
                                  Doctrine_Core::ATTR_ERRMODE        => Doctrine_Core::ERRMODE_SILENT);

The problem is in Query.php line 1417 :

	if ($driverName == 'pgsql' || $driverName == 'oracle' || $driverName == 'oci' || $driverName == 'mssql' || $driverName == 'odbc') {

The driver name declared in Doctrine_Adapter_Oracle not in this conditional.
To resolve this we have to modify the declaration of $attributes in Doctrine_Adapter_Oracle to :

protected $attributes = array(Doctrine_Core::ATTR_DRIVER_NAME    => "oracle",
                                  Doctrine_Core::ATTR_ERRMODE        => Doctrine_Core::ERRMODE_SILENT);

An other problem is probably located at line 1409

 if (($driverName == 'oracle' || $driverName == 'oci') && $this->_isOrderedByJoinedColumn()) {

and 1497

        if (($driverName == 'oracle' || $driverName == 'oci') && $this->_isOrderedByJoinedColumn()) {

if don't correct the declaration of $attributes in Doctrine_Adapter_Oracle.






[DC-1034] ORA-00904 in Doctrine_Connection_Oracle Created: 01/Sep/11  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Blocker
Reporter: Jayson LE PAPE Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Windows 7 64 bits, PHP 5.2.11, Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi, Symfony 1.4.13



 Description   

When i execute this code:

 
$q = Doctrine_Query::create()
            ->from('AGENT ag')
            ->leftJoin('ag.CHANTIER_AGENT cag)
            ->orderBy('ag.nom')
            ->limit(10)
            ->offset(10)
            ->execute();

Doctrine executes :

 
SELECT a.pk AS a__pk, a.ts AS a__ts, a.ck_agent AS a__ck_agent, a.matricule AS a__matricule, a.nom AS a__nom, a.prenom AS a__prenom, a.agent_maitrise AS a__agent_maitrise, 
c.pk AS c__pk, c.ts AS c__ts, c.ck_chantier_agent AS c__ck_chantier_agent, c.ek_chantier AS c__ek_chantier, c.fk_chantier AS c__fk_chantier, c.ek_agent AS c__ek_agent, c.fk_agent AS c__fk_agent 
FROM AGENT a 
LEFT JOIN CHANTIER_AGENT c ON a.ck_agent = c.ek_agent 
WHERE a.ck_agent IN 
(SELECT b.ck_agent 
FROM ( SELECT a.*, ROWNUM AS doctrine_rownum 
FROM ( SELECT DISTINCT a2.ck_agent, a2.nom FROM AGENT a2 LEFT JOIN CHANTIER_AGENT c2 ON a2.ck_agent = c2.ek_agent ORDER BY a2.nom ) 
a2 ) 
b 
WHERE doctrine_rownum BETWEEN 11 AND 20) 
ORDER BY a.nom

The problem is in function _createLimitSubquery in Doctrine_Connection_Oracle :

 
                    $query= 'SELECT '.$this->quoteIdentifier('b').'.'.$column.' FROM ( '.
                                 'SELECT '.$this->quoteIdentifier('a').'.*, ROWNUM AS doctrine_rownum FROM ( '
                                   . $query . ' ) ' . $this->quoteIdentifier('a') . ' '.
                              ' ) ' . $this->quoteIdentifier('b') . ' '.
                              'WHERE doctrine_rownum BETWEEN ' . $min .  ' AND ' . $max;

Error occures, because table name is AGENT and Doctrine give the first letter of the table name for identifier.
To correct this. Use more than one letter in the quoteIdentifier.

 
                    $query = 'SELECT '.$this->quoteIdentifier('limb').'.'.$column.' FROM ( '.
                                 'SELECT '.$this->quoteIdentifier('lima').'.*, ROWNUM AS doctrine_rownum FROM ( '
                                   . $query . ' ) ' . $this->quoteIdentifier('lima') . ' '.
                              ' ) ' . $this->quoteIdentifier('limb') . ' '.
                              'WHERE doctrine_rownum BETWEEN ' . $min .  ' AND ' . $max;





[DC-1031] CLONE -Multiple connections and i18n (raised as unresolved - original ticket marked as resolved) Created: 23/Aug/11  Updated: 28/Mar/12

Status: Open
Project: Doctrine 1
Component/s: Connection, I18n
Affects Version/s: 1.2.2, 1.2.3
Fix Version/s: 1.2.3

Type: Bug Priority: Blocker
Reporter: James Bell Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

MySQL 5.1.37
PHP 5.2.11
symfony 1.2.11 DEV

symfony 1.4.13
PHP 5.3.6
Postgres 8.4.8



 Description   

I used to work with a single database named "doctrine". The query was working properly.

I then decided to use 2 databases so I got my schema like this:

connection: doctrine

Category:
actAs:
I18n:
actAs:
Sluggable:
fields: [name]
Timestampable: ~
fields: [name, description]
columns:
id: ~
name:
type: string(255)
notnull: true
description: string

User:
connection: second
columns:
id: ~
name:
type: string(255)
notnull: true

I did setup my connections in config/databases.yml this way:

all:
doctrine:
// ....
second:
// ....

build-model, build-forms, build-filters and cc got ran. But now, I got an exception saying the "Translation" relation doesn't exist. The Base Models include correctly the bindComponent line:

Doctrine_Manager::getInstance()->bindComponent('Category', 'doctrine');

For now, I managed to kind of fixing it with simply swapping the databases order in my config/databases.yml and it's now working again perfectly.

I forgot to mention that in the CategoryTable when i call $this->getConnection()->getName(), it outputs "second"



 Comments   
Comment by James Bell [ 23/Aug/11 ]

Original issue: DC-363 (http://www.doctrine-project.org/jira/browse/DC-363)

There are some additional comments in there that explain the issue as currently being seen in released versions of Doctrine 1.2. Can I help verify that this is the same ticket?

What is needed to help with debug (in addition to the extra information already provided)?

Comment by Andy.L [ 28/Mar/12 ]

meet the same issue and it really blocked my project, seems no one will maintain 1.x. I'm considering whether to replace symfony 1.4 with 2.0.





[DC-1007] Cannot update a field to NULL with MSSQL connection Created: 25/May/11  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: None
Fix Version/s: None

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

Windows 7 32 bits with Apache 2.2.x, PHP 5.2.17, Sql Server 2008, Symfony 1.4.11 and Doctrine 1.2.4



 Description   

When trying to update a field to NULL in a MSSQL database, Doctrine generates the following request:

    UPDATE table SET fieldThatMustBeNull = , anotherField = 'blabla';

therefore generating a syntax error.

A fix would be to override the update method in the Doctrine_Connection_Mssql and add the following behavior:

Doctrine_Connection_Mssql
    public function update(Doctrine_Table $table, array $fields, array $identifier)
    {
        if (empty($fields)) {
            return false;
        }

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

        $params = array_merge(array_values($fields), array_values($identifier));

        $sql  = 'UPDATE ' . $this->quoteIdentifier($table->getTableName())
              . ' SET ' . implode(', ', $set)
              . ' WHERE ' . implode(' = ? AND ', $this->quoteMultipleIdentifier($table->getIdentifierColumnNames()))
              . ' = ?';

        return $this->exec($sql, $params);
    }





[DC-978] Doctrine_Connection_Mssql dies on modifyLimitSubquery every time Created: 27/Feb/11  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Critical
Reporter: Andrej Pavlovic Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

windows



 Description   

Looking at the latest version of Doctrine_Connection_Mssql in git repo:
https://github.com/doctrine/doctrine1/blob/b4dc8e66a89a7e17cd195c489b18005e19ca9ea5/lib/Doctrine/Connection/Mssql.php

In Doctrine_Query:getLimitSubquery() there is a call to Doctrine_Connection_Mssql::modifyLimitSubquery().

public function modifyLimitSubquery(Doctrine_Table $rootTable, $query, $limit = false, $offset = false, $isManip = false)
{
	return $this->modifyLimitQuery($query, $limit, $offset, $isManip, true);
}

This in turn calls Doctrine_Connection_Mssql::modifyLimitQuery() wihtout passing the $queryOrigin parameter:

    public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false, $isSubQuery = false, Doctrine_Query $queryOrigin = null)
    {
        if ($limit === false || !($limit > 0)) {
            return $query;
        }

        $orderby = stristr($query, 'ORDER BY');

        if ($offset !== false && $orderby === false) {
            throw new Doctrine_Connection_Exception("OFFSET cannot be used in MSSQL without ORDER BY due to emulation reasons.");
        }
        
        $count = intval($limit);
        $offset = intval($offset);

        if ($offset < 0) {
            throw new Doctrine_Connection_Exception("LIMIT argument offset=$offset is not valid");
        }

        $orderbySql = $queryOrigin->getSqlQueryPart('orderby');
        $orderbyDql = $queryOrigin->getDqlPart('orderby');

        if ($orderby !== false) {
            $orders = $this->parseOrderBy(implode(', ', $queryOrigin->getDqlPart('orderby')));

            for ($i = 0; $i < count($orders); $i++) {
...

From just looking at the above code, the query chokes on the first call to a $queryOrigin method. It seems like there is a lot of missing code here which should work with the $query directly when $queryOrigin is not available...

What is the point of $orderbySql and $orderbyDql variables when they are not used anywhere?

This code looks like it's half way done and untested.






[DC-586] Doctrine outputs invalid SQL when using Limit and Order By conditions in MSSQL Created: 18/Mar/10  Updated: 18/Mar/10

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.1
Fix Version/s: None

Type: Bug Priority: Critical
Reporter: Jose Prado Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Windows XP
Apache 2.2
PHP 5.3
Doctrine 1.2.1
Symfony 1.4



 Description   

I have a Doctrine model which connects to a MSSQL database. I was trying to run the following query:

$q = Doctrine_Query::create()
    ->select('*')
    ->from('Comment c')
    ->innerJoin('c.RecordType')
    ->innerJoin('c.Department')
    ->limit(10)
    ->orderBy('c.Counter');

The code failed with a SQL Syntax exception so I took a look at the generated query and found the following (SELECT fields shortened for readabilty):

SELECT * FROM (
	SELECT TOP 10 * FROM (
		SELECT TOP 10 [c].[counter] AS [c__counter], [c].[loanid] AS [c__loanid]... ... ...
		FROM comments c
			INNER JOIN [SystemTypes] [s] ON [c].[recordtype] = [s].[code] AND [s].[fieldname] = 'RecordType'
			INNER JOIN [SystemTypes] [s2] ON [c].[department] = [s2].[code] AND [s2].[fieldname] = 'Department'
		ORDER BY [c].[counter]
	) AS [inner_tbl]
	ORDER BY [inner_tbl].[counter] AS [c__counter] DESC
) AS [outer_tbl]
ORDER BY [outer_tbl].[counter] AS [c__counter] ASC

As you can see, the ORDER BY clauses on the inner_tbl and outer_tbl segments have AS clauses which do not belong there. If you fix the ORDER BY statements the query runs just fine.

So I decided to prod around the Mssql.php connection class and found the following:

140 public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false, $isSubQuery = false)
141 {
...
169                    $field_array = explode(',', $fields_string);
170                    $field_array = array_shift($field_array);
171                    $aux2 = preg_split('/ as /', $field_array);
172                    $aux2 = explode('.', end($aux2));
173
174                    $aliases[$i] = trim(end($aux2));
...
232 }

Line 171 seems to be in charge of setting up the orderBy aliases but it is looking for a lower case ' as ' string which doesn't exist in this SQL expression. Changing that to a case insensitive regular expression search seems to fix the problem:

171                    $aux2 = preg_split('/ as /i', $field_array);

Here is the resulting SQL with the change:

SELECT * FROM (
	SELECT TOP 10 * FROM (
		SELECT TOP 10 [c].[counter] AS [c__counter], [c].[loanid] AS [c__loanid]... ... ...
		FROM comments c
			INNER JOIN [SystemTypes] [s] ON [c].[recordtype] = [s].[code] AND [s].[fieldname] = 'RecordType'
			INNER JOIN [SystemTypes] [s2] ON [c].[department] = [s2].[code] AND [s2].[fieldname] = 'Department'
		ORDER BY [c].[counter]
	) AS [inner_tbl]
	ORDER BY [inner_tbl].[c__counter] DESC
) AS [outer_tbl]
ORDER BY [outer_tbl].[c__counter] ASC]

This seems to fix the problem but I don't know if it'll create a regression. It's a start though. Anyone have any thoughts on this?






[DC-1048] MSSQL Connection Created: 16/Jan/12  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Constantine Tkachenko Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Microsoft Windows Server 2008 R2; IIS 7; PHP 2.3.8; Doctrine 1.2.4; Symfony 1.4.16



 Description   

Function spliti(); is deprecated.
It need to be change to (in my own opinion):

$field_array = str_ireplace(' as ', ' as ', $field_array);
$aux2 = explode(' as ', $field_array);

thnx.






[DC-998] MySQL Driver possibly subject to sql injections with PDO::quote() Created: 19/Apr/11  Updated: 17/Apr/14

Status: Open
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, 1.2.0-BETA2, 1.2.0-BETA3, 1.2.0-RC1, 1.2.0, 1.2.1, 1.2.2, 1.2.3
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Anthony Ferrara Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

All



 Description   

Prior to 5.3.6, the MySQL PDO driver ignored the character set parameter to options. Due to MySQL's C api (and MySQLND), this is required for the proper function of mysql_real_escape_string() (the C API call). Since PDO uses the mres() C call for PDO::quote(), this means that the quoted string does not take into account the connection character set.

Starting with 5.3.6, that was fixed. So now if you pass the proper character set to PDO via driver options, sql injection is impossible while using the PDO::quote() api call.

PDO proof of concept
$dsn = 'mysql:dbname=INFORMATION_SCHEMA;host=127.0.0.1;charset=GBK;';
$pdo = new PDO($dsn, $user, $pass);
$pdo->exec('SET NAMES GBK');
$string = chr(0xbf) . chr(0x27) . ' OR 1 = 1; /*';
$sql = "SELECT TABLE_NAME
            FROM INFORMATION_SCHEMA.TABLES
            WHERE TABLE_NAME LIKE ".$pdo->quote($string)." LIMIT 1;";
$stmt = $pdo->query($sql);
var_dump($stmt->rowCount());

Expected Result: `int(0)`.
Actual Result: `int(1)`.

There are 2 issues to fix. First, the documentation does not indicate that you can pass the `charset` option to the MySQL Driver. This should be fixed so that users are given the proper option to set character sets.

Secondly, `Connection::setCharset()` should be modified for MySQL to throw an exception, since the character set is only safely setable using the DSN with PDO. This is a limitation of the driver and could be asked as a feature request for the PHP core. Either that, or a big warning should be put on the documentation of the API to indicate the unsafe character set change

Note that this is the same issue reported for Doctrine2 with link: http://www.doctrine-project.org/jira/browse/DBAL-111



 Comments   
Comment by Fabien Potencier [ 23/May/11 ]

Any news on this one? It has been "fixed" in Doctrine2 and must be also fixed in Doctrine1.





[DC-989] Doctrine_Connection::execute() and Doctrine_Connection::exec() fail if Doctrine_Event::skipOperation() is triggered Created: 22/Mar/11  Updated: 22/Mar/11

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

Type: Bug Priority: Major
Reporter: David Dixon Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None


 Description   

In order to generate SQL from migrations, an event listener was attached to the migration system to monitor for preQuery and preExec events.

In an attempt to prevent the migration from additionally writing the query to the database, the skipOperation method was triggered, and supposedly allowed for n the execute() and exec() methods of Doctrine_Connection

eg. Doctrine_Connection::execute()
 
$this->getAttribute(Doctrine_Core::ATTR_LISTENER)->preQuery($event);

if ( ! $event->skipOperation) {
    $stmt = $this->dbh->query($query);
    $this->_count++;
}
$this->getAttribute(Doctrine_Core::ATTR_LISTENER)->postQuery($event);

unfortunately setting this option in the event listener breaks execution of the migration system as the $count/$stmtn variables (used in the methods) are no longer defined, triggering E_NOTICE, and the fetch* methods (eg fetchColumn) also break as they are chaining methods without testing for the return. theerfore, even if the $stmnt variable was created as initially null, the system would still throw an E_FATAL as the NULL variable doest provide the ::fetchColumn() methods (etc).

Quite a serious flaw as 2 areas of code do not provide a consistent approach to how to work with events.






[DC-960] Bug in OCI8 adapter's freeCursor function causes exception with HYDRATE_ON_DEMAND Created: 26/Jan/11  Updated: 17/Apr/14

Status: Open
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, 1.2.0-BETA2, 1.2.0-BETA3, 1.2.0-RC1, 1.2.0, 1.2.1, 1.2.2, 1.2.3
Fix Version/s: None

Type: Bug Priority: Major
Reporter: vadik56 Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

doctrine, symfony, linux, hpux


Attachments: File closeCursor.diff    

 Description   

oci_free_statement should be changed to oci_cancel inside Doctrine_Adapter_Statement_Oracle::closeCursor(). Otherwise exception is thrown if HYDRATE_ON_DEMAND is used followed by foreach loop.

Doctrine2 should also be affected by this bug.

Change:
public function closeCursor()

{ $this->bindParams = array(); return oci_free_statement($this->statement); }

To:
public function closeCursor()

{ $this->bindParams = array(); return oci_cancel($this->statement); }




[DC-917] Doctrine take wrong connction Created: 05/Nov/10  Updated: 05/Nov/10

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Volodymyr Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I have problems with different connection
i am using doctrine with symfony, and i work with 2 connections
in base class i have bind to my connection

Doctrine_Manager::getInstance()->bindComponent('Datasource', 'doctrine');

symfony generate me

$this->datasources = Doctrine_Core::getTable('datasource')
->createQuery('a')
->execute();

and when i execute it show me error error that can find this table but it take wrong connection

by test i tried to add bind component as datasource (first is lower character and it works pretty cool)

then i change getTable('datasource') => getTable('Datasource') but it doesn't work
then i have added
test function to my datasource table

public static function test()

{ return Doctrine_Query::create()->from("Datasource")->execute(); }

and it works.






[DC-881] Doctrine_Manager::parsePdoDsn() doesn't work properly [+patch] Created: 08/Oct/10  Updated: 17/Apr/14

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

Type: Bug Priority: Major
Reporter: Enrico Stahn Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Doctrine_Manager::parsePdoDsn('dblib:host=127.0.0.1:1433;dbname=foo') does not return proper results.

patch and test case @ github






[DC-863] Connection.UnitOfWork::buildFlushTree when loading data from yml file, Incorrect ordering of tables by their relations Created: 10/Sep/10  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection, Data Fixtures
Affects Version/s: 1.2.0, 1.2.1, 1.2.2, 1.2.3
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Ochoo Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 1
Labels: None
Environment:

symfony 1.4.6, windows 7, apache2.2, php5.3.3, mySQL 5.1.49-community


Attachments: File schema.yml     File test.yml    

 Description   

I don't know where exactly to start, I'm new here, and i'm not even sure this is a bug. BUT

We have a database structure with most important tables' PK's as string fields, which function as FK on other tables the basic structure is:

Artist
-Album
-Song
-Comments

each artist has multiple songs
each artist has multiple albums
each album has multiple songs that belong to the same artist as the album belongs to
each song has multiple comments

thus, the UnitOfWork - builtFlushTree should generate

[0]=>Artist
[1]=>Album
[2]=>Song
[3]=>Comments

but instead i get:
[0] => Album
[1] => Artist
[2] => Song
[3] => Lyrics

which in turn generates:

QLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`lyrics`.`album`, CONSTRAINT `album_artist_fk_stripped_name_artist_stripped_name` FOREIGN KEY (`artist_fk_stripped_name`) REFERENCES `artist` (`stripped_name`) ON DELETE CASCADE ON UPDATE CASC)
obviously.

I've been going through symfony/doctrine code for a whole day trying to figure out why I can't load-data. in the end i get to this buildFlushTree function.
probably have to go deeper. but so far this is it

PS. It's my decision to use string fields as PK's and FK even though it's a bad practice, but just because it is a bad practice I shouldn't be unable to work with it.



 Comments   
Comment by Ochoo [ 10/Sep/10 ]

found a tiny BUG, submitting the fix.

EDIT: scratch the rest from here.

<!-----------
still, fixing the bug does not resolve the issue
BECAUSE:
the whole logic of ordering the tables is flawed! it can be proved, don't have time to do so. but trying to come up with a fix myself

instead of looping through the tables and then through each tables' related tables, either have a recursive function OR implement user defined array sort function, latter of which seems like the proper and correct way to go
-->

Comment by Ochoo [ 10/Sep/10 ]

unfortunately i'm unable to commit any changes i have made. just me being a newbie, any help is appreciated

Comment by Ochoo [ 10/Sep/10 ]

on UnitOfWork.php of Doctrine ORM 1.2.3
Revision 7684
right after the line 752:
array_splice($flushList, $index, 0, $relatedClassName);
there should be:
$index++;

Comment by atali daoud [ 29/Nov/10 ]

@Ochoo: Even with your bugfix, it doesn't seem to work.

Comment by Ochoo [ 01/Dec/10 ]

thanks atali, i haven't checked it on 1.2.3, just did and you're right. the "bug fix" worked on 1.2.0 but not on 1.2.3. I'm gonna look into it, at least i'll try. but this is a bug right?





[DC-841] Doctrine_Connection_Mssql::replaceBoundParamsWithInlineValuesInQuery regex failing to replace all '?' instances [patch+] Created: 25/Aug/10  Updated: 05/Mar/11

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

Type: Bug Priority: Major
Reporter: Daniel Cousineau Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 3
Labels: None
Environment:

PHP 5.2.11, Apache, Microsoft SQL Server 2005



 Description   

When executing queries with WHERE statements using multiple instances of the "<>" operator (as well as other non =,( symbols inbetween definitions), the method Doctrine_Connection_Mssql::replaceBoundParamsWithInlineValuesInQuery fails to identify all ? replacements.

In the following piece of code I have a query (trimmed for readability and renamed for privacy) that fails to have all "?" symbols replaced as well as the relevant code from the method mentioned above (minus the return statement) doing a simple demonstration:

<?php 
$query = "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <> ? AND [t].[field2] <> ? AND [t].[field2] LIKE ?)";

$params = array(
	"'param1'",
	"'param2'",
	"'param3'"
);


/**
 * Replaces bound parameters and their placeholders with explicit values.
 *
 * Workaround for http://bugs.php.net/36561
 *
 * @param string $query
 * @param array $params
 */
//protected function replaceBoundParamsWithInlineValuesInQuery($query, array $params) {

	foreach($params as $key => $value) {
		if(is_null($value)) {
			$value = 'NULL';
		}
		else {
			//$value = $this->quote($value); //REMOVED AS PRE-ADDED QUOTES TO ABOVE PARAMETER LIST
		}

		$re = '/([=,\(][^\\\']*)(\?)/iU';
		
		$matches = array();
		preg_match($re,$query,$matches);
		
		var_dump($matches); //ADDED FOR DEMONSTRATION

		$query = preg_replace($re, "\\1 {$value}", $query, 1);
		
		var_dump($query); //ADDED FOR DEMONSTRATION
	}

//	return $query;
//
//}

Running this code produces:

array(3) {
  [0]=>
  string(18) "([t].[field1] <> ?"
  [1]=>
  string(17) "([t].[field1] <> "
  [2]=>
  string(1) "?"
}
string(108) "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <>  'param1' AND [t].[field2] <> ? AND [t].[field2] LIKE ?)"
array(0) {
}
string(108) "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <>  'param1' AND [t].[field2] <> ? AND [t].[field2] LIKE ?)"
array(0) {
}
string(108) "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <>  'param1' AND [t].[field2] <> ? AND [t].[field2] LIKE ?)"

Unfortunately the regex will not identify all the ? instances properly in the query when run like preg_match_all(), which was my first idea to fix (pre-identify all ? instances, then go through and replace them).

The only 3 potential solutions I can think of are:

1. Pre-identify all ?'s and note their position in the string, to do this using a much looser regex, then replace all the ?'s found
2. Use a stack a loop and a switch statement to scan for eligible ? replacements. I have some sample code that shows this should work, but performance is not something I have tested.
3. Revert back to the previous behavior. Scanning the changelogs I really don't know where this broke, other than queries that worked prior to 1.2.3 have since broken and this method is the cause.



 Comments   
Comment by Daniel Cousineau [ 25/Aug/10 ]

I am probably way over thinking a solutions, however since I have to run home and don't have time to flesh this out further at the moment, my initial idea is something like this:

<?php 
$query = "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <> 'Testing!?' AND [t].[field2] <> ? AND [t].[field?] LIKE ? AND [t].[field3] = ?)";

$params = array(
	"'param1'",
	"param2?",
	"'param3'"
);

var_dump($query);

$stack = array();
$stringDelim = array("'", '"');

$i = 0;
foreach( str_split($query) as $char )
{
	switch($char) {
		
		case "[":
			if( !in_array(end($stack), $stringDelim) )
				array_push($stack, $char);
			
			break;
			
		case "]":
			if( end($stack) == "[" ) {
				array_pop($stack);
			} else
				array_push($stack, $char);
				
			break;
		
		case "\"":
		case "'":
			if( end($stack) == $char )
				array_pop($stack);
			else
				array_push($stack, $char);
			
			break;
		
		case "?":
			if( !in_array(end($stack), array_merge($stringDelim, array("[", "]"))) )
			{
				$param = array_shift($params);
				$query = substr_replace($query, $param, $i, 1);
				
				$i += strlen($param) - 1;
				var_dump($query);
			}
			
			
			break;
		
		default:
	}
	
	$i++;
}

var_dump($query);

Which produces

string(131) "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <> 'Testing!?' AND [t].[field2] <> ? AND [t].[field?] LIKE ? AND [t].[field3] = ?)"
string(138) "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <> 'Testing!?' AND [t].[field2] <> 'param1' AND [t].[field?] LIKE ? AND [t].[field3] = ?)"
string(144) "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <> 'Testing!?' AND [t].[field2] <> 'param1' AND [t].[field?] LIKE param2? AND [t].[field3] = ?)"
string(151) "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <> 'Testing!?' AND [t].[field2] <> 'param1' AND [t].[field?] LIKE param2? AND [t].[field3] = 'param3')"
string(151) "SELECT * FROM [table] AS [t] WHERE ([t].[field1] <> 'Testing!?' AND [t].[field2] <> 'param1' AND [t].[field?] LIKE param2? AND [t].[field3] = 'param3')"

Which is what we would expect, as well as it doesn't take into account for newly inserted data containing '?' symbols.

But again this is just playing around with potential solutions.

Comment by Enrico Stahn [ 27/Aug/10 ]

The patch for DC-545 broke some queries or didn't worked at all. Unfortunately there was no Test Case for DC-545.

The patch and a Test Case can be found at: http://github.com/estahn/doctrine1/compare/master...DC-841

Comment by Enrico Stahn [ 02/Sep/10 ]

I made a mistake with github, the updated branch can be found at
http://github.com/estahn/doctrine1/tree/DC-841-2

Comment by Lionel ROTA [ 05/Mar/11 ]

Doesn't work with :

'Test' <> 'Test !?'

The question mark is captured...

This code seems working :

foreach($params as $key => $value) {
  if(is_null($value)) {
    $value = 'NULL';
  }
  else {
    $value = $this->quote($value);
  }

  $re = '/((?:[=<>,\(]|LIKE|IS)[^\\\']*)(\?)/iuU';

  $query = preg_replace($re, "\\1 {$value}", $query, 1);
}




[DC-777] getConnectionForComponent and bindComponent are case sensitive Created: 07/Jul/10  Updated: 07/Jul/10

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

Type: Bug Priority: Major
Reporter: Marcel Berteler Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Symfony 1.4.x
sfDoctrinePlugin


Attachments: Text File doctrine_manager.patch    

 Description   

When using multiple database connections, the sfDoctrinePlugin for Symfony 1.4.x is case sensitive when looking up the connection for a model / component while the Symfony is not.

This causes code to function correct even when the model names are used in lower case. Once a second connection is configured, the model name is registered in upper case via the base-class (as per the naming convention) causing the wrong connection to be chosen when the model is referenced in lower case.

This:

 
$componentName = 'Country';

$this->_bound[$componentName] = $connectionName;

Will result in no connection found for:

 
$componentName = 'country';

if (isset($this->_bound[$componentName])) {
            return $this->getConnection($this->_bound[$componentName]);
        }

Unless this was purposely designed to be case-sensitive, I think this should be changed to prevent confusion since in general PHP is not case sensitive when dealing with variable names.

This bug is related to http://www.doctrine-project.org/jira/browse/DC-740






[DC-773] Connection::createQuery() can use wrong connection Created: 01/Jul/10  Updated: 01/Jul/10

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

Type: Bug Priority: Major
Reporter: Lonny Kapelushnik Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 1
Labels: None

Attachments: File DC773TestCase.php     Text File DC_773.patch    

 Description   

Similar to bug DC-437 (http://www.doctrine-project.org/jira/browse/DC-437)
When calling Connection::createQuery() object we use the default connection instead of the connection we have when calling the createQuery() method.



 Comments   
Comment by Lonny Kapelushnik [ 01/Jul/10 ]

Patch and Test Case





[DC-740] issue with multiple connection handling Created: 16/Jun/10  Updated: 16/Nov/10

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

Type: Bug Priority: Major
Reporter: Ian P. Christian Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 3
Labels: None

Attachments: Text File doctrine_core.patch     Text File doctrine_manager.patch    
Sub-Tasks:
Key
Summary
Type
Status
Assignee
DC-618 [PATCH] Local key relations without m... Sub-task Open Jonathan H. Wage  

 Description   

I've found an issue where doctrine will use the wrong connection for tables under certain conditions.

In a template, I'm doing a $sf_user->hasCredential() - which is causing this to be run in sfGuardSecurityUser,

$this->user = Doctrine::getTable('sfGuardUser')->find($id);

When this execute, the calls find themselves to Doctrine_Manager::getConnectionForComponent($componentName)

This method calls Doctrine_Core::modelsAutoload($componentName);, which fails to load the class, and returns false (no checking is done to see if it should return true).

As this fails to include the sfGuardUser classes wher the component binding goes on, the getTAble call will use the default connection, then create the table fails to use the correct connection

Doctrine_Core::getTable()

return Doctrine_Manager::getInstance()->getConnectionForComponent($componentName)->getTable($componentName);

the binding is done after the call to getConectionForComponent, as it's getTable that will ultimately cause the autoloader to pull in the table classes.



 Comments   
Comment by Jonathan H. Wage [ 16/Jun/10 ]

Hmm, why is the autoloading of sfGuardUser failing? I don't understand that part. If it is failing do you get a cannot load class error?

Comment by Ian P. Christian [ 16/Jun/10 ]

The reason no autoload error is throw, is because symfony's autoloader loads the class for you, but it does it at the getTable() call, which as seen below from Doctrine_Core::getTable(), it's proxied though the connection - which is created before the gable is instanced, which of when the file is actaully loaded.

return Doctrine_Manager::getInstance()->getConnectionForComponent($componentName)->getTable($componentName);
Comment by Ian P. Christian [ 16/Jun/10 ]

Just to expand on this...

This obviously gets called when a call to getTable is made:

    public function getConnectionForComponent($componentName)
    {
        Doctrine_Core::modelsAutoload($componentName);

        if (isset($this->_bound[$componentName])) {
            return $this->getConnection($this->_bound[$componentName]);
        }

        return $this->getCurrentConnection();
    }

The autoload fails, as you can see from the code...

    public static function modelsAutoload($className)
    {
        if (class_exists($className, false) || interface_exists($className, false)) {
            return false;
        }

        if ( ! self::$_modelsDirectory) {
            $loadedModels = self::$_loadedModelFiles;

            if (isset($loadedModels[$className]) && file_exists($loadedModels[$className])) {
                require $loadedModels[$className];

                return true;
            }
        } else {
            $class = self::$_modelsDirectory . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

            if (file_exists($class)) {
                require $class;

                return true;
            }
        }
        return false;
    }

$_modelsDirectory is never set, and $_loadedModelFiles is an empty array. The $_modelsDirectory, even if set, wouldn't handle loading for plugins, which put their models in places like lib/model/doctrine/sfDoctrineGuardPlugin/sfGuardUser.class.php.

Comment by Ian P. Christian [ 16/Jun/10 ]

This was not a problem before r7668 (at least, not for most use cases)....

It used to be that null was passed as the first arg in the D_Query::create() method call, causing the query to figure out itself which connection to use, which was done after the component was bound, so that's fine!

However, the code below is how it is in the current head

    public function createQuery($alias = '')
    {
        if ( ! empty($alias)) {
            $alias = ' ' . trim($alias);
        }

        $class = $this->getAttribute(Doctrine_Core::ATTR_QUERY_CLASS);

        return Doctrine_Query::create($this->_conn, $class)
            ->from($this->getComponentName() . $alias);
    }

Here , the connection of the table (as explained above is previously set incorerctly) is passed to the query.

Comment by Ian P. Christian [ 16/Jun/10 ]

I've found a work around to this, not sure if it's a desirable fix though...

In the project configuration class, I've added this to the setup()


    $this->dispatcher->connect('doctrine.configure', array($this, 'doctrineBinder'));

and the following method is also added, were I'm manually doing my bindings...

  public function doctrineBinder(sfEvent $event)
  {
    $manager = Doctrine_Manager::getInstance();
    $manager->bindComponent('sfGuardUser', 'nosp');
    $manager->bindComponent('Incident', 'nosp');
    $manager->bindComponent('ServiceIp', 'ip');

  }

The overhead here isn't really that high (it just sets an element in the array) - I'd also wonder if a bindComponents($array); should be added to simplify this call, but that's another method.

Comment by Marcel Berteler [ 06/Jul/10 ]

After a long and hard look at the sfDoctrinePlugin and Doctrine code I can to the same conclusion. The Doctrine autoload is not working in sfDoctrinePlugin. I think this is more a sfDoctrinePlugin bug than a Doctrine bug.

Instead of manual binding, a better way is the actually make sure the intended flow of the code is working like it should be.

To be able to use sfDoctrineGuard with multiple connections you need to ensure that the connection name is added to the Schema of sfDoctrineGuard. Once this is done, rebuilding the model will put a bindComponent in the class files.

This works fine if the autoload is working like it should.

To get the autoload to work, you can extend the autoload function of Doctrine_Core in Doctrine:

The Doctrine.php file is empty by default, so its easy to add your code to it (until the problem is fixed without having to edit Doctrine code)

lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine.php:

 
class Doctrine extends Doctrine_Core
{
  public static function modelsAutoload($className)
  {
    sfAutoload::getInstance()->autoload($className);

    parent::modelsAutoload($className);
  }
  
}
Comment by Marcel Berteler [ 06/Jul/10 ]

Sorry... the above does not work.

Doctrine_Core->autoload() is called and not Doctrine->autoload().

sfAutoload::getInstance()->autoload($className);

can be added to Doctrine_Core line 1133

public static function modelsAutoload($className)
    {
        if (class_exists($className, false) || interface_exists($className, false)) {
            return false;
        }

        sfAutoload::getInstance()->autoload($className);
Comment by Marcel Berteler [ 06/Jul/10 ]

Oh, and to make sfDoctrineGuard work properly, you might have to ensure the sfBasicSecurityUser is bound to the correct model.

You can do this in plugins\sfDoctrineGuardPlugin\lib\user\sfGuardSecurityUser.class.php or in apps\xxxxx\lib\myUser.class.php

 
Doctrine_Manager::getInstance()->bindComponent('sfGuardUser', 'connectionName');
Comment by Marcel Berteler [ 07/Jul/10 ]

The patch to Doctrine_Core

This is a hack that only works when used in sfDoctrinePlugin / Symfony

Not intended as the final patch to fix this bug but as a work around to make multiple connections usable.

Comment by Ian P. Christian [ 08/Jul/10 ]

This effects migrations too it seems:

Even doing this:


    $manager = Doctrine_Manager::getInstance();                                                          
    $manager->bindComponent('ChangeRequest', 'nosp');                                                    
    $manager->bindComponent('change_request', 'nosp');                                                   
class Addstatetochangerequest extends Doctrine_Migration_Base                                            
{                                                                                                        
  public function up()                                                                                   
  {                                                                                                      
    $this->addColumn('change_request', 'change_state', 'enum', array('values' => array('draft', 'submitted', 'approved', 'rejected', 'closed')));

This results in:


# ./symfony doctrine:migrate
>> doctrine  Migrating from version 0 to 1
                                                                                                                                                                                    
  The following errors occurred:                                                                                                                                                    
                                                                                                                                                                                    
   - SQLSTATE[42S02]: Base table or view not found: 1146 Table 'nosp_test_radius2.change_request' doesn't exist. Failing Query: "ALTER TABLE change_request ADD change_state TEXT"  

The database attempted to be used there is not the correct one.

Comment by Marcel Berteler [ 27/Sep/10 ]

second required patch to make Symfony work with 2 concurrent databases

Comment by Eugeniy Belyaev [ 21/Oct/10 ]
Another bad way to get it working in symfony:


ProjectConfiguration.class.php
  public function configureDoctrine(Doctrine_Manager $manager)
  {
    $files = sfFinder::type('file')
      ->maxdepth(0)
      ->not_name('*Table.class.php')
      ->name('*.class.php')
      ->in(sfConfig::get('sf_lib_dir') . '/model/doctrine');

    foreach ($files as $file) {
      $class_name = str_replace('.class.php', '', basename($file));
      Doctrine_Core::loadModel($class_name, $file);
    }
  }
Comment by Dean de Bree [ 16/Nov/10 ]

I found that if I changed the getTable function inside the Core.php file it seemed to work. Basically it forces the autoloader to load the object file, and when it does this it runs the bound connection statement to bind a table to a connection.

Core.php
/**
     * Get the Doctrine_Table object for the passed model
     *
     * @param string $componentName
     * @return Doctrine_Table
     */
    public static function getTable($componentName)
    {
        if (!class_exists($componentName)) {
            new $componentName();
        }

        return Doctrine_Manager::getInstance()->getConnectionForComponent($componentName)->getTable($componentName);
    }




[DC-668] Call to undefined method Doctrine_Adapter_Mysqli::setAttribute() Created: 06/May/10  Updated: 08/Jun/10

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

Type: Bug Priority: Major
Reporter: nadim Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

windows xp, apache2.2 web server, php5.3.1, doctrine1.2.2, zend framework 1.10.3, mysql 5.1



 Description   

i'm trying to switch to php5.3.1.
using the same connection as before, mysql://, i get

Warning: PDO::__construct() [pdo.--construct]: OK packet 6 bytes shorter than expected in C:\wamp\bin\php\php5.2.9-2\PEAR\Doctrine\lib\Doctrine\Connection.php on line 470

after researching this error, i found out that it is related to the new password in mysql5.
i tried changing the password for the connection, and made sure there is no old_password set in my.ini, without any success.

so i'm trying to connect using mysqli adapter, and now i get this error:
PHP Fatal error: Call to undefined method Doctrine_Adapter_Mysqli::setAttribute() in C:\wamp\bin\php\php5.2.9-2\PEAR\Doctrine\lib\Doctrine\Connection.php on line 496

how can i connect to mysql5.1 with php5.3, and what is the best connection to pick. mysql or mysqli.



 Comments   
Comment by Jonathan H. Wage [ 08/Jun/10 ]

What is Doctrine_Adapter_Mysqli? Is this your own class?





issue with multiple connection handling (DC-740)

[DC-618] [PATCH] Local key relations without modifed fields but with modified relations are not saved Created: 06/Apr/10  Updated: 10/Jul/11

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

Type: Sub-task Priority: Major
Reporter: Bernhard Schussek Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 1
Labels: None

Attachments: File DC618TestCase.php     GIF File directadmin-logo.gif     Text File ticket_dc618.patch    

 Description   

Assume the following test setup:

[Email] * — 1 [Author] 1 — * [Book]

Assume further that you have a new Email, Author and Book object. Email and book have modified fields, author does not, except for the foreign key relation.

Now, when you save the Email object, the related Author is not saved because isModified($deep = false) returns false since no local field is modified. The solution is to pass the parameter $deep = true to isModified().

Patch and test case are attached. No existing test is broken by this fix.

PS: This patch fixes the correlated bug that objects with I18N behaviour are not saved if only their Translation objects are modified, but not their own fields.






[DC-541] MSSQL Server: Enabling MARS prevents the saving of records. Created: 03/Mar/10  Updated: 10/Jun/10

Status: Open
Project: Doctrine 1
Component/s: Connection, Record
Affects Version/s: 1.2.1
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Craig Marvelley Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 1
Labels: None
Environment:

PHP 5.3.1
MSSQL Server 2008
Windows
PHP PDO ODBC


Attachments: File index.php     Text File mssql_transaction.patch    

 Description   

This is related to issue #540. In order to circumvent that issue, I enabled MARS (Multiple Active Result Sets) - now when attempting to save any record the following error results:

Fatal error: Uncaught exception 'Doctrine_Transaction_Exception' with message 'Rollback failed. There is no active transaction.' in C:\www\doctrine\lib\Doctrine\Transaction.php on line 319

This is actually caused by the following MSSQL error:

exception 'Doctrine_Transaction_Exception' with message 'SQLSTATE[42000]: Syntax error or access violation: 3997 [Microsoft][SQL Server Native Client 10.0][SQL Server]A transaction that was started in a MARS batch is still active at the end of the batch. The transaction is rolled back. (SQLExecDirect[3997] at ext\pdo_odbc\odbc_driver.c:247)' in C:\www\doctrine\lib\Doctrine\Transaction.php:212 Stack trace: #0 C:\www\doctrine\lib\Doctrine\Transaction.php(511): Doctrine_Transaction->beginTransaction(NULL) #1 C:\www\doctrine\lib\Doctrine\Connection.php(1377): Doctrine_Transaction->beginInternalTransaction(NULL) #2 C:\www\doctrine\lib\Doctrine\Connection\UnitOfWork.php(64): Doctrine_Connection->beginInternalTransaction() #3 C:\www\doctrine\lib\Doctrine\Record.php(1691): Doctrine_Connection_UnitOfWork->saveGraph(Object(Model)) #4 C:\www\doctrine\tools\sandbox\index.php(83): Doctrine_Record->save() #5

{main}

I haven't worked out what's going on yet, but this blog post may shed some light on it:
http://blogs.msdn.com/cbiyikoglu/archive/2006/11/21/mars-transactions-and-sql-error-3997-3988-or-3983.aspx

I've attached a script to reproduce this issue in the sandbox (MARS is enabled in the DSN).



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

We'll need some more information. We don't have a way to test against mssql currently.

Comment by Craig Marvelley [ 16/Mar/10 ]

I've dug a little deeper and it seems that the exception is thrown because the Doctrine_Transaction_Mssql class has overrides for the transaction begin/commit/rollback methods. When I remove these overrides and let transactions be handled through the PDO API I don't get any exceptions while transactions seem to function as normal.

Why are these methods overridden? Is it perhaps only necessary for the MSSQL PDO extension, as suggested here (http://trac.symfony-project.org/wiki/HowToConnectToMSSQLServer), since that extension seemingly has no native transaction support (I've never used it)? Perhaps this isn't necessary for the ODBC extension?

Comment by Craig Marvelley [ 16/Mar/10 ]

This patch maintains the existing manual transaction functionality for MSSQL connections, but uses the native PDO API for ODBC connections.

Comment by Jonathan H. Wage [ 08/Jun/10 ]

Hmm. I don't think this patch is good. It doesn't fix the problem, just hacks around it.

Comment by Craig Marvelley [ 08/Jun/10 ]

Ok.. Do you have any recommendations for a better patch? While I agree my patch is far from elegant, it does at least allow MSSQL and ODBC to work alongside each other. As far as I can tell, the underlying issue is that Doctrine uses the same driver for two very different PDO extensions - I couldn't think of a way to resolve this issue without some kind of check as to which extension is in use.

We could maybe catch the exception that's thrown in the first instance when running a manual query, and try calling the parent rollback method instead? Maybe only when the current connection is ODBC? That's essentially the same approach though, with the added overhead of an unnecessary query that we know will fail..

I'm very keen to find a fix that you're happy with for this since I've been manually patching it for a while, so any feedback that would engender that would be great!

Comment by Jonathan H. Wage [ 08/Jun/10 ]

I am still not sure of the exact problem/error that is happening. When isn't happening with the current code? or is something happening that should not?

Comment by Craig Marvelley [ 09/Jun/10 ]

As far as I understand it (I'm no SQL Server expert, unfortunately!) the issue is this:

The Doctrine_Transaction_Mssql class is used for both the MSSQL and ODBC PDO extensions. It manages transactions by executing manual queries against the database (ROLLBACK TRANSACTION, COMMIT_TRANSACTION, etc.).

This isn't compatible with the ODBC PDO extension and SQL Server when Multiple Active Record Sets is enabled; I believe MARS allows multiple transactions to co-exist, and this query-style way of managing them isn't compatible with that as transactions aren't 'namespaced'. MARS is critical because without it there's no way of looping over more than one record set at the same time, something we take for granted in MySQL et al.

From that link to the Symfony wiki I posted earlier, it appears that the query method of managing transactions is only necessary for the MSSQL PDO extension - quote:

"dblib doesn't support transactions so we need to add a workaround for transactions, last insert ID, and quoting"

This is backed up by the patch - when we let the ODBC driver handle transactions natively, everything works fine.

Does that make sense?

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

Now that I look at everything again, do we need to even be overriding those methods at all in Doctrine_Transaction_Mssql (_doRollback, _doCommit, _doBeginTransaction). We should just let the database driver handle it?

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

Index: lib/Doctrine/Transaction/Mssql.php
===================================================================
--- lib/Doctrine/Transaction/Mssql.php	(revision 7673)
+++ lib/Doctrine/Transaction/Mssql.php	(working copy)
@@ -65,28 +65,4 @@
 
         $this->conn->execute($query);
     }
-    
-    /**
-     * Performs the rollback.
-     */
-    protected function _doRollback()
-    {
-        $this->conn->getDbh()->exec('ROLLBACK TRANSACTION');
-    }
-    
-    /**
-     * Performs the commit.
-     */
-    protected function _doCommit()
-    {
-        $this->conn->getDbh()->exec('COMMIT TRANSACTION');
-    }
-    
-    /**
-     * Begins a database transaction.
-     */
-    protected function _doBeginTransaction()
-    {
-        $this->conn->getDbh()->exec('BEGIN TRANSACTION');
-    }
 }

It seems like we don't even need to do that?

Comment by Craig Marvelley [ 10/Jun/10 ]

For ODBC, we definitely don't. That link suggests the above approach caters to the MSSQL extension. I've not tried that one because I'm on Windows and as you probably know it's not recommended; I imagine I'd have way too many other problems were I to try! I didn't want to break anything for anyone using the MSSQL driver though, which led to my awkward patch.

From my point of view, I'd imagine the majority of people using SQL Server will be using a Windows stack, and therefore ODBC (and possibly the new SQL Server Driver for PHP PDO extension, which definitely won't need manual queries, in future) - so I'd favour an approach that didn't compromise those drivers.

As an aside - are there any plans afoot to support the new Microsoft endorsed driver? I imagine if you guys were to do so it would be for Doctrine 2, but do you know of any community effort to get it working in 1.2?





[DC-509] Oracle don't close cursor Created: 18/Feb/10  Updated: 28/Jul/11

Status: Reopened
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.1
Fix Version/s: None

Type: Bug Priority: Major
Reporter: oxman Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 1
Labels: None
Environment:

PHP 5.3.1



 Description   

When you doing a big loop of insertion you have a "too many open cursor".
The problem is in Doctrine_Connection class
At line 1005 you should replace :
$stmt = $this->prepare($query);
by
$stmt = $this->dbh->prepare($query);

and at line 1041 you should replace :
$stmt = $this->prepare($query);
by
$stmt = $this->dbh->prepare($query);

After this correction, you never have the problem "too many open cursor"

Thanks to Ota to point that on google groups.
http://groups.google.com/group/doctrine-user/browse_thread/thread/fe6cd03c8fb18b64/728ec1b4e42b1f0b?lnk=gst&q=doctrine_oracle_adapter#728ec1b4e42b1f0b



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

Hmm. This change is invalid because it then doesn't return the proper statement object. What is the real issue we get the too many cursors open error?

Comment by oxman [ 04/Mar/10 ]

Why ?
The both return Doctrine_Adapter_Statement_Interface

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

The change makes it so they return PDOStatement, and we need it to return the Doctrine statement wrapper, right?

Comment by oxman [ 04/Mar/10 ]

It seems not.

At line 1005 in Doctrine/Connection.php :
$stmt = $this->dbh->prepare($query);
var_dump(get_class($stmt));
die;

I see :
string(33) "Doctrine_Adapter_Statement_Oracle"

And with :
$stmt = $this->prepare($query);
var_dump(get_class($stmt));
die;

I see :
string(29) "Doctrine_Connection_Statement"

The both implements Doctrine_Adapter_Statement_Interface

Comment by vincent [ 29/Apr/10 ]

I have this problem in Symfony 1.4.3 when I use comand:
symfony doctrine:data-load

I have 3000 - 4000 lines in my fixtures and max open cursor at 300 on my database oracle.

This problem can an issue???

Comment by Jonathan H. Wage [ 08/Jun/10 ]

I see, well the change still is not right because it bypasses all the logic in Doctrine_Connection::prepare() which is for sure required and can't just be removed. We need to determine the real issue here in order to properly patch it.

Comment by Peter Wooster [ 29/Jun/10 ]

I'm encountering the same ORA-1000 problem running the symfony doctrine:build-schema command. We are still using PDO, but I have asked in the users group if that's the best choice. The problem is that the listTableColumns and listTableRelations methods both leave a cursor open. They both call Connection::fetchAssoc, so they should be reading all the records.

I narrowed it down a little:

This works properly when no parameters are provided:

$sql = "SELECT * FROM all_tab_columns tc WHERE tc.table_name = 'DEAL'";
$result = $connection->fetchAssoc($sql, array());

This doesn't release the cursor when a named parameter is provided

$sql = "SELECT * FROM all_tab_columns tc WHERE tc.table_name = :tn";
$result = $connection->fetchAssoc($sql, array(':tn' => 'DEAL')); // doesn't release cursor

This doesn't release the cursor when a positional parameter is provided

$sql = "SELECT * FROM all_tab_columns tc WHERE tc.table_name = ?";
$result = $connection->fetchAssoc($sql, array('DEAL')); // doesn't release cursor

This works properly when the PDO connection is used directly

$sql = "SELECT * FROM all_tab_columns tc WHERE tc.table_name = :tn";
$dbh = $connection->getDbh();
$stmt = $dbh->prepare($sql);
$stmt->execute(array(':tn' => 'DEAL'));
$result = $stmt->fetchAll();

Comment by Clément Herreman [ 28/Jul/11 ]

As I went through this bug, I looked for a fix. I found one here https://github.com/derflocki/doctrine1/commit/47b926a523f9f6e3b88042ef2939af0646285ea2

Basically it consist of freeing cursors that aren't used by a SELECT query, thus preventing Oracle from throwing an exception on batch insert/delete.





[DC-375] Doctrine_Table getTable singleton issue Created: 22/Dec/09  Updated: 22/Dec/09

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.0.14
Fix Version/s: None

Type: Bug Priority: Major
Reporter: ben bi Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

symfony 1.2.9



 Description   

first, i defined a table class :
class CohibaClientTable extends Doctrine_Table
{
public $_pager;

public function getAbstractList($arrParam = array(), $page=1, $maxPerPage=20)
{
$objQuery = $this->createQuery('t1')
->select('t1.*');

if(is_array($arrParam) && count($arrParam)>0)

{ QueryAssistant::processOption($objQuery, $arrParam); // dont set "offset" and "limit" option in it }

$this->_pager = new Doctrine_Pager($objQuery, $page, $maxPerPage);

$items = $this->_pager->execute();

$objQuery->free();
return $items;
}

public function getList($page=1, $maxPerPage=20)

{ $arrParam = array( 'orderBy'=>'t1.cle asc' ); return $this->getAbstractList($arrParam, $page, $maxPerPage); }

public function getPager()

{ return $this->_pager; }

}

and then, in the action, invoke it like this codes:
1>
$items = Doctrine::getTable("CohibaClient")->getList(1, $maxPerPage);
$pager = Doctrine::getTable("CohibaClient")->getPager();

$this->log("total records: ".$pager->getNumResults()." total page: ".$pager->getLastPage()."\n");
$lastPage = $pager->getLastPage();
2>
$table = Doctrine::getTable("CohibaClient");
$items = $table->getList(1, $maxPerPage);
$pager = $table->getPager();

$this->log("total records: ".$pager->getNumResults()." total page: ".$pager->getLastPage()."\n");
$lastPage = $pager->getLastPage();

#2 works, but not #1, error is "Fatal error: Call to a member function getNumResults() on a non-object in.... " is it an issue when singleton generation?






[DC-355] Call to a member function evictAll() if a table is retrieved, that is not existent Created: 12/Dec/09  Updated: 12/Dec/09

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.0, 1.2.1
Fix Version/s: None

Type: Bug Priority: Major
Reporter: aNj Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Ubuntu 8.04



 Description   

Hi!

Im not quite sure it this bahaviour is wanted, but i think that this
should be catched:

If i call Doctrine::getTable on a non existing model, the exception is
thrown. After them i want always to clear all Record Repositories, see
code:

try

{ $table = Doctrine::getTable('notexistent'); }

catch(Exception $e)

{ echo 'not existent'.$e->getMessage(); }

Doctrine_Manager::connection()->clear();

Then I get the error message:

Fatal error: Call to a member function evictAll() on a non-object in /
core/lib/Doctrine/Doctrine/Connection.php on line 1239

The problem is that the function clear doesnt check if a repository is
given.

public function clear()
{
foreach ($this->tables as $k => $table)

{ $table->getRepository()->evictAll(); // getRepository delivers FALSE $table->clear(); }

}

Is it normal behaviour? Or should it be checked first:

if ($repository = $table->getRepository())

{ $repository->evisctAll(); }

best regards,
aNj






[DC-373] Relating to Translation table (generated by Doctrine_I18n) doesn't work correctly after resetting connection Created: 20/Dec/09  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection, I18n
Affects Version/s: 1.2.1, 1.2.2, 1.2.3
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Kousuke Ebihara Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 2
Labels: None
Environment:

PHP 5.2.11 (with Suhosin-Patch 0.9.7)
PHP 5.3.6


Attachments: File DC373TestCase.php    

 Description   

Relating to Translation table (generated by Doctrine_I18n) doesn't work correctly after resetting connection.

First, I defined the following schema.yml::

 
  Example:
    actAs:
      I18n:
        fields: [title]
    columns:
        title: string(128)

Next, I prepared the following fixture file::

 
  Example:
    Example_1:
      Translation:
        en:
          title: "Title"
        ja:
          title: "題名"

Next, I run "build-all-reload" task. The table was created and data was loaded.

And I write the following code::

 
  Doctrine_Core::loadModels('models');
  $example = Doctrine_Core::getTable('Example')->find(1);
  
  var_dump(
    $example->Translation['en']->title,
    $example->Translation['ja']->title
  );
  
  Doctrine_Manager::resetInstance();
  Doctrine_Manager::getInstance()->openConnection(DSN, 'doctrine');
  
  $example2 = Doctrine_Core::getTable('Example')->find(1);
  var_dump(
    $example2->Translation['en']->title,
    $example2->Translation['ja']->title
  );

I try executing my code, but I got the following error::

  string(5) "Title"
  string(6) "題名"
  
  Doctrine_Connection_Mysql_Exception: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'e.title' in 'field list' in /path/to/doctrine/Doctrine/Connection.php on line 1082
  
  Call Stack:
      0.0055      65352   1. {main}() /path/to/my/code/test.php:0
      0.2776    5873388   2. Doctrine_Table->find() /path/to/my/code/test.php:52
      0.2793    5881152   3. Doctrine_Query->fetchOne() /path/to/doctrine/Doctrine/Table.php:1611
      0.2793    5881296   4. Doctrine_Query_Abstract->execute() /path/to/doctrine/Doctrine/Query.php:281
      0.2793    5881892   5. Doctrine_Query_Abstract->_execute() /path/to/doctrine/Doctrine/Query/Abstract.php:1026
      0.3127    5890712   6. Doctrine_Connection->execute() /path/to/doctrine/Doctrine/Query/Abstract.php:976
      0.3164    5892632   7. Doctrine_Connection_Statement->execute() /path/to/doctrine/Doctrine/Connection.php:1006
      0.3181    5907408   8. Doctrine_Connection->rethrowException() /path/to/doctrine/Doctrine/Connection/Statement.php:269


 Comments   
Comment by Arnaud Charlier [ 02/Nov/10 ]

Good Morning,

First, thanks a lot for your work on Doctrine. It's a real great tool we love to use.

Currently in one of our big application we have exactly the same issue.
It seems when we close the connection, the reference with the objectTranslation is lost.
Re-open the connection seems not able to reinstantiate this Translation link to the objectTranslation.

Currently we have no solution, but we are still investigating this.

I'm available to go deep in the code with you, but any Doctrine Team help will be really nice.

Thanks to let me know as soon as possible.

Arnaud

Comment by Joe Siponen [ 27/May/11 ]

I've just now battled with the very same problem in Doctrine 1.2 (the version bundled with symfony 1.4) and the problem seems to be caused by the fact that Doctrine_Record_Generator simply isn't written such that it is able to reinitialize generators for unloaded table instances after a connection is closed. This problem also manifests itself after a table has been loaded in a connection and one tries retrieve a table again after Doctrine_Connection->evictTables() has been called. This makes it impossible to to open more than one connection at a time in a request/script when using behaviors that dynamically modify table instances (such as the i18n behavior).

Doctrine_Record_Generator determines if it needs to run its initialization methods simply by checking if the to-be generated class, as defined by the className option, exists using a class_exists call. This means that the first time this method is called the initialization happens but for every subsequent call no initialization is made. Now, in the i18m behavior, the important initialization happens in its setTableDefinition method in which it removes any of the translated fields from the table instance that is been setup and redefines them as relations on the to-be-created Translation class. It then finishes off by dynamically declaring the new class for the translation record using its generateClassFromTable method.

Thus, the first time everything goes smoothly and the i18n generator's setTableDefinition is called and the table instance is properly initialized. Everything will now work as expected while the current connection is open since the connection instance keeps the i18n modified table instances alive and well for callers.

But, when the current connection is closed the i18n modified table instances it holds are also removed (goes out of scope). Then, when a new connection is opened, this new connection will start without having any table instances. This means that the next time one asks the new connection for a table instance of the same class with the i18n behavior the i18n behaviors will fail to initialize because the generator at this time believes its class has actually been initialized which, in turn, means that the table using the i18n behavior isn't properly initialized. No initialization means that this table will now include the non-existant i18n fields in the select part of its queries (those are in the translation table) causing those queries to fail miserably.

I believe this could be fixed by adding a static attribute to Doctrine_Record_Generator that tracks the spl_object_hash of the underlying dbh instance variable of the doctrine connection of the table parameter. If the hash is the same the next time that the initialize method is called the generator can decide not to reinitialize itself but if it detects that the hash of the current connection is different then that is definitely a clue to the generator that it needs to reinitialize itself (i.e. run all of the initialization methods but generateClassFromTable which should't be called more than once).

Maybe do it like this perhaps:

 
abstract class Doctrine_Record_Generator extends Doctrine_Record_Abstract
{
  public function initialize(Doctrine_Table $table)
  {
    /* ... */ 
  
    $currentConnectionHash = spl_object_hash($table->getConnection()->getDbh());
    
    //Next part is called if this is the first connection made or if this is a new open connection with new table instances
    if ($currentConnectionHash != self::$lastConnectionHash)
    {
      self::$lastConnectionHash = $currentConnectionHash;
      
      $this->buildTable();

      $fk = $this->buildForeignKeys($this->_options['table']);

      $this->_table->setColumns($fk);

      $this->buildRelation();

      $this->setTableDefinition();
      $this->setUp();
      
      if ($this->_options['generateFiles'] === false && class_exists($this->_options['className'])) {
        $this->generateClassFromTable($this->_table); //Don't generate the class more than once ever
      }
      
      $this->buildChildDefinitions();

      $this->_table->initIdentifier();
    }
  }
}
Comment by Joe Siponen [ 16/Jun/11 ]

Failing test case attached

Comment by Kousuke Ebihara [ 08/Jun/12 ]

Good job, Joe Siponen! Thanks for your nice patch!

I can't understand why the Doctrine team discontinued maintenance of Doctrine 1 without any fixes for some serious issues like this problem...

Joe, would you send your patch by pull-request in GitHub? They might notice this problem and try to fix in official repository by your request. If you cannnot, I will do it as your proxy. (Of course I'm going to describe your credit)

Comment by Kousuke Ebihara [ 11/Sep/12 ]

I've tested Joe Siponen's patch, it would be good in a situation of single connection, but it doesn't work in multiple connections.

So I modified your patch to fit my needs. I'm testing my arranged patch and I want to publish it ASAP...





[DC-370] Doctrine serializes arrays, objects, etc. like 'string', which is never bigger than a TEXT, limited to 65535 characters (in MySQL) Created: 19/Dec/09  Updated: 29/Jan/10

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.1
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Tom Boutell Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Doctrine supports storing objects and arrays, and implements this via serialize().

However in DataDict/Mysql they are handled like the 'string' type, which means they are subject to the rules there that ensure nothing bigger than a 'TEXT' is ever used to represent them.

TEXT is not a great choice for objects and arrays because it's difficult to ensure they will not exceed 65,535 bytes in size.

This would be most easily fixed by moving them to the next block of case statements there, used for CLOBs. The logic there already picks suitable large types (MEDIUMTEXT and LONGTEXT) as needed, and defaults to LONGTEXT which is a good choice for objects and arrays.



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

Array and Object data types now behave identically to clob.

See r7077

Comment by Tom Boutell [ 29/Jan/10 ]

Thanks David!





[DC-280] Add pre/postHydrateResultSet() events Created: 23/Nov/09  Updated: 08/Jun/10

Status: Open
Project: Doctrine 1
Component/s: Connection, Query, Record
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Major
Reporter: Adam Jensen Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Over the last several weeks I've been working on streamlining the access control logic in the application I'm working on, and I realized that Doctrine's event listeners might be able to help. For more detailed background information take a look at http://groups.google.com:80/group/dallasphp/browse_thread/thread/91e3f107cd611adf ...but here's the problem in a nutshell:

Since my application's access control logic is all implemented in PHP rather than in the database (i.e., I can't add access control to my queries as a simple WHERE clause), I'm looking for a way to hook into the query process just after the records have been hydrated and actually modify the result set that gets returned, such that only permissible records show up in the final result set.

Unfortunately, although there are several listener methods that look promising for this, none of them seem to have access to the data being returned. For instance, if I run a custom query via Doctrine_Query::execute(), the postQuery() hook definitely runs ...but it doesn't give me access to anything but the query string itself.

Since, in some instances (e.g., hydration listeners), the Doctrine_Event object is assigned arbitrary data that the listener can modify, I'm wondering if the same thing couldn't be done more universally?



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

In Doctrine 1.2 you can create custom hydrators. You can extend the core hydrators to remove the data you want? I think that would work.

Comment by Adam Jensen [ 24/Nov/09 ]

Sure enough, that does the trick!

There are a couple of downsides, though, that might be worth considering in terms of future development:

1. It would be nice to be able to specify constructor arguments for the hydrator, so that collaborators can be injected. In my example, the hydrator needs access to the application's access control list object; currently it's simply retrieving it from a global registry, but it would be nice for testing's sake to be able to inject it instead.
2. It would also be nice to be able to chain multiple hydrators together; that's one reason I was looking at listeners, since they've got that capability already. That approach allows you to keep distinct behavior distinct a lot more easily.

Ultimately, I'd still kind of like to see another listener method available ...say, preHydrateResultSet() and postHydrateResultSet()? I think that would be a more flexible approach, even though the custom hydrator solution works quite well.

Thanks!
Adam

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

I like the idea. I'll move this to 1.3. I don't think we're gonna have a 1.3 version but if we do, it'll be there.

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

We can include this in a 1.2.x release if you would like to provide a patch and some tests. Thanks, Jon





[DC-975] Treat sql server error 2601 as Doctrine_Core::ERR_ALREADY_EXISTS Created: 17/Feb/11  Updated: 17/Feb/11

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

Type: Improvement Priority: Minor
Reporter: Ben Davies Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Sql server


Attachments: Text File Doctrine_Connection_Mssql_Exception.patch    

 Description   

Patch attached to treat sql server error 2601 (Integrity constraint violation) as Doctrine_Core::ERR_ALREADY_EXISTS






[DC-894] Typo in Doctrine_Manager::getConnectionDrivers() Created: 19/Oct/10  Updated: 19/Oct/10

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

Type: Bug Priority: Minor
Reporter: Akitaka Kohno Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 1
Labels: None
Environment:

symfony 1.4 / PHP 5.2.13 / CentOS5.4



 Description   

Hello.

getConnectionDrivers is returning member variable '_connectionsDrivers' at line 809.
It's probably typo, I think this variable name should be '_connectionDrivers'.






[DC-879] MSSQL - missing function date_part() in Expression/Mssql.php [+patch] Created: 05/Oct/10  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.2, 1.2.3
Fix Version/s: None

Type: Improvement Priority: Minor
Reporter: Enrico Stahn Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Missing function date_part() in Expression/Mssql.php. I don't know why the set of expressions is different for each driver. This makes it hard to develop database independent.






[DC-861] Make sure doctrine uses the right connection when creating a query from a table object Created: 08/Sep/10  Updated: 08/Sep/10

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

Type: Improvement Priority: Minor
Reporter: Emmanuel Delescolle Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None
Environment:

All



 Description   

Line# 1036
When using Table::createQuery, null is specified as the connection when calling Doctrine_Query::create() which results in using the default connection while the "correct" connection can be know ($this->getConnection())

here is the fix:

— a/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Table.php
+++ b/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Table.php
@@ -1033,7 +1033,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable

$class = $this->getAttribute(Doctrine_Core::ATTR_QUERY_CLASS);

  • return Doctrine_Query::create(null, $class)
    + return Doctrine_Query::create($this->getConnection(), $class)
    >from($this>getComponentName() . $alias);
    }





[DC-843] MSSQL - Equal-to Operator doesn't work with columns of type text in where condition [+patch] Created: 26/Aug/10  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.2, 1.2.3
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: Enrico Stahn Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Example:

Doctrine::getTable('Ticket_DCXXX2_Model')->findByUsernameAndFoo('foo', 'bar');

foo is of type "text". Doctrine generates "where .... foo = 'bar'", but this will throw an mssql exception because you cant use the equal to operator in mssql for text and varchar types. Doctrine should consider this database related behavoir, shouldn't it?



 Comments   
Comment by Enrico Stahn [ 26/Aug/10 ]

TestCase added http://github.com/estahn/doctrine1/compare/master...DC-843

Comment by Enrico Stahn [ 27/Aug/10 ]

Patch added to github (see above)

commit msg: DC-843 fix (TestCase need fix for DC-841 to run successfully)

Comment by Enrico Stahn [ 02/Sep/10 ]

I made a mistake with github, the updated branch can be found at
http://github.com/estahn/doctrine1/tree/DC-843-2





[DC-808] Doctrine_Connection_Statement->execute() Do not pass failing query to Doctrine_Connection->rethrowException() Created: 05/Aug/10  Updated: 05/Aug/10

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

Type: Improvement Priority: Minor
Reporter: Alexandre Ravey Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File Doctrine_Connection_Statement.patch    

 Description   

When Doctrine_Connection_Statement->execute() fail on a query, Exception is rethrown by Doctrine_Connection.

But the failing query is not passed to rethrowException() as third parameter, which make debug very difficult.

See attached patch file to correct this.






[DC-840] MSSQL - strange behavior with multiple addWhere conditions and ">" [+patch] Created: 25/Aug/10  Updated: 17/Apr/14

Status: Open
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.2, 1.2.3
Fix Version/s: None

Type: Bug Priority: Trivial
Reporter: Enrico Stahn Assignee: Jonathan H. Wage
Resolution: Unresolved Votes: 0
Labels: None


 Description   

In the first example below the second parameter wasn't replaced by the given value. I tracked it down and i suppose it's because of the ">" sign. It's the same for "<". Equal-Operator (=) works fine.

        $q = Doctrine_Query::create()
            ->select('password, modified_at')
            ->from('Ticket_DCXXX_Model')
            ->andWhere('password = ?', 'abc')
            ->andWhere('modified_at > ?', '2010-01-01')
SELECT [t].[id] AS [t__id], [t].[password] AS [t__password], [t].[modified_at] AS [t__modified_at]
FROM [ticket__d_c_x_x_x__model] [t]
WHERE ([t].[password] =  'abc' AND [t].[modified_at] > ?)
        $q = Doctrine_Query::create()
            ->select('password, modified_at')
            ->from('Ticket_DCXXX_Model')
            ->andWhere('modified_at > ?', '2010-01-01')
            ->andWhere('password = ?', 'abc')
SELECT [t].[id] AS [t__id], [t].[password] AS [t__password], [t].[modified_at] AS [t__modified_at]
FROM [ticket__d_c_x_x_x__model] [t]
WHERE ([t].[modified_at] >  '2010-01-01' AND [t].[password] =  'abc')


 Comments   
Comment by Enrico Stahn [ 25/Aug/10 ]

http://github.com/estahn/doctrine1/compare/master...DC-840

Comment by Enrico Stahn [ 27/Aug/10 ]

see DC-841





Generated at Tue Sep 30 22:06:10 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.