Yii Framework Forum: Trying to get table alias regularly crashes - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • This topic is locked

Trying to get table alias regularly crashes Too much memory? Tried to allocate 20 bytes ?! Rate Topic: -----

#1 User is offline   mintao 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 62
  • Joined: 02-December 09
  • Location:Munich, Germany

Posted 02 May 2010 - 06:47 AM

Hi,

I'm working a lot with (default) scopes. Often when I try to get the table alias, it crashes - telling me, that the allowed memory size is exhausted. E.g.:

Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 20 bytes) in /.../yii/framework/db/ar/CActiveRecord.php  on line 1206


This is an example query in the controller:
Product::model()->with('prices')->findByPk(4);


This is my Product.php code:
...
public function defaultScope()
{
    return array(
        'condition' => sprintf('`%s`.`is_active` = 1', $this->getTableAlias()),
    );
}

public function relations()
{
    'prices' => array(self::HAS_MANY, 'Price', 'product_id'),
}


This is my Prices.php code:
...
public function defaultScope()
{
    return array(
        'condition' => sprintf('`%s`.`is_active` = 1', $this->getTableAlias()),
    );
}


So the SQL query should look sth like this (pseudo code)
SELECT a.*, b.* FROM Product a, JOIN Price b WHERE a.id=4 AND a.active=1 AND b.active=1


Any suggestions? Did I miss sth?
0

#2 User is offline   mintao 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 62
  • Joined: 02-December 09
  • Location:Munich, Germany

Posted 02 May 2010 - 07:36 AM

Update: Seems that this method already causes the memory overflow:
$this->getDbCriteria(false)


I set the memory usage up to 1GB (in php.ini), but same effect: Memory usage is growing until 1GB, then the process get interrupted. Looks like an endless loop.
0

#3 User is offline   mintao 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 62
  • Joined: 02-December 09
  • Location:Munich, Germany

Posted 02 May 2010 - 07:54 AM

OK, got it.

The method getTableAlias calls getDbCriteria that calls defaultScope, which is calling getDbCriteria.

So an endless loop :(

But what is the right approach to get the upper mentioned request done?
We have:
  • 2 tables,
  • 2 models,
  • 2 same called columns,
  • 2 defaultScopes.


The only solution I have in mind is to ensure that every column of my 92 tables has a unique name. But that's not the way I want to spend the next 2 weeks.

Seems that it's a bug anyway. Or am I wrong?
0

#4 User is offline   samdark 

  • Having fun
  • Yii
  • Group: Yii Dev Team
  • Posts: 3,726
  • Joined: 17-January 09
  • Location:Russia

Posted 02 May 2010 - 04:03 PM

Looks interesting. Could you create a minimalistic test case so we can reproduce it?
Yii 1.1 Application Development Cookbook

Enjoying Yii? Star us at github: 1.1 and 2.0.
0

#5 User is offline   mintao 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 62
  • Joined: 02-December 09
  • Location:Munich, Germany

Posted 02 May 2010 - 05:28 PM

Thanks Samdark for your answer. I think we don't need a test scenario here.
The only question is: How do I get the table alias for my defaultScope()?
The method $this->getTableAlias() causes an endless loop in "CActiveRecord"
0

#6 User is offline   samdark 

  • Having fun
  • Yii
  • Group: Yii Dev Team
  • Posts: 3,726
  • Joined: 17-January 09
  • Location:Russia

Posted 02 May 2010 - 06:22 PM

Hmmm… yes, it seems it can't be done with current code.

I've created new issue ticket for this case: http://code.google.c.../detail?id=1183
Yii 1.1 Application Development Cookbook

Enjoying Yii? Star us at github: 1.1 and 2.0.
0

#7 User is offline   mintao 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 62
  • Joined: 02-December 09
  • Location:Munich, Germany

Posted 02 May 2010 - 07:02 PM

Thanks for that.

I tried to find a work around: My idea was to override the default alias `t` whith the table name. So I created a parent model class which extends from CActiveRecord and contains only this method:

class ActiveRecord extends CActiveRecord
{
    public function defaultScope()
    {
        $criteria = new CDbCriteria;
        $criteria->alias = $this->tableName();
        return $criteria;
    }
}


Every model now extends from ActiveRecord. The defaultScope method is tweaked like this:

[...]
public function defaultScope()
{
    // Only return actire records
    $criteria = parent::defaultScope();
    $criteria->condition = sprintf('`%s`.`is_active` = :active', $criteria->alias);
    $criteria->params = array(':active' => true);
    return $criteria;
}


This works - well - sometimes ;)
After an extatic change of my models (I thought I had the solution), I figured out another problem:
Fatal error: Cannot use object of type CDbCriteria as array in /.../yii/framework/db/ar/CActiveRecord.php  on line 1703


Is this another bug, or is a CDbCriteria object not allowed for scopes? Do you have an idea how to continue programming anyway?
0

#8 User is offline   samdark 

  • Having fun
  • Yii
  • Group: Yii Dev Team
  • Posts: 3,726
  • Joined: 17-January 09
  • Location:Russia

Posted 02 May 2010 - 07:21 PM

Normally defaultScope returns an array that is later used to instantiate CDbCriteria.

In your case it's probably better to use named scope instead of defaultScope:
public function active()
{
    $this->getDbCriteria()->mergeWith(array(
        'condition' => sprintf('`%s`.`is_active` = 1', $this->getTableAlias()),
    ));
    return $this;
}


Product::model()->active()->with('prices')->findByPk(4);

Yii 1.1 Application Development Cookbook

Enjoying Yii? Star us at github: 1.1 and 2.0.
0

#9 User is offline   mintao 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 62
  • Joined: 02-December 09
  • Location:Munich, Germany

Posted 02 May 2010 - 07:47 PM

That's my prior version. ;)
The user can activate or deactivate (is_active),
an email address only can be used if verified via activation link
and a foto can be banned by the support team.
So the defaultScope often looks like "where is_active=1 and is_banned=0 and is_verified=1".
So I don't want to create such a long pipe (...->active()->notBanned()->verified()) in every controller action. The possibility is too high to forget one scope.

But - I found an easier solution/work around:
public function defaultScope()
{
    return array(
        'alias' => $this->tableName(),
        'condition' => sprintf('`%s`.`is_active` = 1', $this->tableName())
    );
}

1

#10 User is offline   mintao 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 62
  • Joined: 02-December 09
  • Location:Munich, Germany

Posted 08 May 2010 - 01:02 PM

Addition to my last post:

This doesn't work when one tries to fetch a record by its primary key. My SQL log then reads like that:

SELECT * FROM `Product` `Product` WHERE (`Product`.`is_active` = 1)  AND (`t`.`id` = 23);


Unnecessary to say, that the table alias `t` breaks it all down :(

PS: Therefore I already opened a ticket
0

#11 User is offline   mintao 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 62
  • Joined: 02-December 09
  • Location:Munich, Germany

Posted 14 May 2010 - 06:59 PM

Ticket is closed, problem is solved. Thank you!
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • This topic is locked

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users