Ticket #1116 (closed defect: fixed)

Opened 22 months ago

Last modified 19 months ago

preSelect and mysql bug

Reported by: tuct Owned by: jwage
Priority: major Milestone:
Component: Attributes Version: 0.11.0
Severity: Keywords:
Cc: Has Test:
Status: Has Patch:

Description (last modified by tuct) (diff)

i use symfony 1.1 and the trunk from the sfDoctrinePlugin. my problem is that with doctrine alone the Query is extended well (Where deleted = 0 ) but as soon as i try it with the symfony plugin and symfony the 0 in the params part get lost and the query messed up:

i have tried to write a test for doctrine alone but i won't fail only if i use it with symfony.

then i created a new symfony project with only one table:

User:
  columns:
    id:
      primary: true
      autoincrement: true
      type: integer(4)
    username:
      type: string(255)
  actAs:
    SoftDelete:

and tried the query:

    $q = new Doctrine_Query();
    $q->select('u.*')
    ->from('User u')
    ->where('u.id = ?',array(1));
    return $q->fetchOne();

it fails with: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

[ SELECT u ..... FROM User u WHERE u.id = ? AND s.deleted = ?', array(1) <- see the missing 0 ]

when i revert to [4477] everything works

[4478] breaks it again

thats why i posted it here cause the changes seems to be in doctrine core not in the plugin

the tests i attched are a try to show my performance issue concerning the dqlHooks but i found this first

class Doctrine_Ticket_Tobi_TestCase extends Doctrine_UnitTestCase 
{
  public function prepareTables()
  {
    $this->tables[] = 'Ticket_9999_Style';
    $this->tables[] = 'Ticket_9999_StyleAlias';
    parent::prepareTables();
  }

  public function testTicket()
  {
    $style = new Ticket_9999_Style();
    $style->name = 'test';
    $style->save();
    //$this->conn->clear();
    $style =  Doctrine::getTable('Ticket_9999_Style')->find('1');
    $styleAliases =  $style->Aliases;
    $this->assertEqual($style->name, 'test');
    $this->assertEqual($styleAliases[0]->name, 'test');
    // try again!
    $this->conn->clear();
 
    $q = new Doctrine_Query();
    $q->select('s.*')
    ->from('Ticket_9999_Style s, s.Aliases sa')
    ->where('sa.name = ?', array('test'));
    
    $test =  $q->fetchOne();
    $this->assertEqual($test, 'test');
        
  }
}

class Ticket_9999_Style extends Doctrine_Record
{
  public function setTableDefinition()
  {
    $this->setTableName('style');
    $this->hasColumn('id', 'integer', 4, array('primary' => true, 'notnull' => true, 'autoincrement' => true));
    $this->hasColumn('name', 'string', 255);
    $this->hasColumn('description', 'string', 2147483647);
    $this->hasColumn('style_count', 'integer', 4);
    $this->hasColumn('created_by', 'integer', 4);
    $this->option('type', 'INNODB');
    $this->option('collate', 'utf8_general_ci');
    $this->option('charset', 'utf8');
  }

  public function setUp()
  {
    parent::setUp();
    $this->hasMany('Ticket_9999_StyleAlias as Aliases', array('local' => 'id',
                                                              'foreign' => 'style_id'));

    $timestampable0 = new Doctrine_Template_Timestampable();
    $softdelete0 = new Doctrine_Template_SoftDelete();
    $this->actAs($timestampable0);
    $this->actAs($softdelete0);

  }
  public function preInsert($event)
  {
    $normlized_name = normalizeStyle($this->name);
    $alias = Doctrine::getTable('Ticket_9999_StyleAlias')->findOneByName($normlized_name);
    if($alias instanceof Ticket_9999_StyleAlias){
      $this->getErrorStack()->add('name', '"'.$normlized_name.'" exists already in Ticket_9999_StyleAlias');
      $event->skipOperation();
    }
  }
  
  public function postInsert($event)
  {
    if($this['id']){
      $this->addAlias($this->name);
    }
  } 
  public function addAlias($name)
  {
    $name = normalizeStyle($name);
    $alias = Doctrine::getTable('Ticket_9999_StyleAlias')->findOneByName($name);
    if(!($alias instanceof Ticket_9999_StyleAlias)){
      $alias = new Ticket_9999_StyleAlias();
      $alias->name = $name;
      $alias->style_id = $this['id'];
      $alias->save();   
    }
    return $alias;
  }    
}

class Ticket_9999_StyleAlias extends Doctrine_Record
{
  public function setTableDefinition()
  {
    $this->setTableName('style_alias');
    $this->hasColumn('name', 'string', 255, array('primary' => true, 'unique' => true));
    $this->hasColumn('style_id', 'integer', 4, array('primary' => true));

    $this->option('type', 'INNODB');
    $this->option('collate', 'utf8_general_ci');
    $this->option('charset', 'utf8');
  }

  public function setUp()
  {
    parent::setUp();
    $this->hasOne('Ticket_9999_Style as Style', array('local' => 'style_id',
                                                      'foreign' => 'id'));
  }
}
class Ticket_9999_StyleTable extends Doctrine_Table
{
  public static function findByName($name)
  {
    echo "findByName";
    $q = new Doctrine_Query();
    $q->select('s.*')
    ->from('Ticket_9999_Style s, s.Aliases sa')
    ->where('sa.name = ?');
    return $q->fetchOne(array(normalizeStyle($name)));
  }


}
function normalizeStyle($alias){
  return(strtolower(str_replace(array(',',' ',''','"','`',''','|','-','_'),'',$alias)));
}

Attachments

1116TestCase.php Download (1.7 KB) - added by tuct 22 months ago.

Change History

Changed 22 months ago by jwage

Can you create a failing test case for ticket #1116 that tests for this exception "SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens" ?

I updated test coverage in r4480 for the SoftDelete? behavior and I am not able to produce the error you are getting.

Changed 22 months ago by jwage

  • milestone changed from 0.11.3 to 0.11.1

Changed 22 months ago by tuct

i am not able to produce this error within the tests, cause after a few hours of searching i found that it only happens with mysql not with sqlite ....

here is a little test script that produces the exception when used with mysql, just change the dns to an empty but existing database (no data is needed to produce the error) and the path to Doctrine.php

<?php
error_reporting(E_ALL | E_STRICT);
ini_set('max_execution_time', 900);
ini_set('date.timezone', 'GMT+0');


require_once 'Doctrine.php';  
spl_autoload_register(array('Doctrine', 'autoload'));
Doctrine_Manager::connection('mysql://user:password@localhost/testing');  //switch to sqlite and the error is gone :(
//Doctrine_Manager::connection(new PDO('sqlite::memory:'));


class User extends Doctrine_Record
{

  public function setTableDefinition()
  {
    $this->setTableName('user');
    $this->hasColumn('id', 'integer', 4, array('primary' => true, 'autoincrement' => true));
    $this->hasColumn('username', 'string', 255);
    $this->hasColumn('password', 'string', 255);
  }

  public function setUp()
  {
    parent::setUp();
    $softdelete0 = new Doctrine_Template_SoftDelete();
    $this->actAs($softdelete0);
  }

}
Doctrine_Manager::connection()->export->exportClasses(array('User'));

//This works!
$q = new Doctrine_Query();
$q->select('s.*')
  ->from('User s')
  ->where('s.username = ?', array('tobi'));
$q->getSql(); // <-just added this line for debuging
$test =  $q->fetchOne();
echo "works so far
";
    
//this will not work!
$q = new Doctrine_Query();
$q->select('s.*')
  ->from('User s')
  ->where('s.username = ?', array('tobi'));
//$q->getSql();   
$test =  $q->fetchOne();    
   
echo "don't work with mysql!";

Changed 22 months ago by jwage

If you use a Mock adapter for the connection you can check the sql generated with mysql.

Check out Doctrine_Ticket_642_TestCase, Doctrine_Ticket_950_TestCase, Doctrine_Ticket_963_TestCase, Doctrine_Query_MysqlSubqueryHaving_TestCase

They all have some examples of using the mock adapters to check the sql and params that would be executed.

Changed 22 months ago by tuct

the testcase does not trigger the exception "SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens"

but it shows why it is triggered (the params are wrong)

if u switch to a real db the exception is triggered

hope that helps

Changed 22 months ago by tuct

Changed 22 months ago by tuct

  • description modified (diff)
  • summary changed from preSelect and sfDoctrinePlugin (trunk) bug to preSelect and mysql bug

Changed 22 months ago by guilhermeblanco

  • status changed from new to closed
  • resolution set to fixed

In r4488 I commented this ticket.

Actually the URL I pointed tells the issue was fixed in 2007, not 2008. I researched a bit more and discovered the issue is still alive, in a report done in 4/june/2008. Check out:  http://bugs.php.net/bug.php?id=45169

I'm closing this ticket. If you have any possible solution, feel free to reopen it and post a patch.

Changed 22 months ago by jwage

(In [4491]) fixes #1116

Changed 19 months ago by anonymous

  • milestone New deleted

Milestone New deleted

Note: See TracTickets for help on using tickets.