PDO->query(); Allowed memory exhousted

Hello,

I have moved my website to new server and got this problem,

on CDbCommand class, queryInternal method, $this->_statement=$this->getConnection()->getPdoInstance()->query($this->getText()); line(298), yii executes query SHOW CREATE TABLE table, and on pdo->query() there comes Allowed memory size of 16777216 bytes exhausted error. What can be wrong with that?

JFF

Well, this is a error from PHP. It tells you that the script you are trying to run needs more memory than you allow scripts to allocate on execution. So you have two options:

[list=1]

[*] increase the memory limit (somewhere in php.ini)

[*] or optimize your application so it uses less memory

[/list]

I do not think that increasing memory limit will solve the problem.

And SQL query is SHOW CREATE TABLE table (follows from calling Post::model()->FindAll()), so it shouldn’t require so much memory.

I can’t tell you where the problem is located. But you could do a test and insert a




echo memory_get_usage();



before the call to the database class. I guess it will already be somewhere near that limit.

The show table query really shouldn’t be problematic, Post::model()->FindAll() is more likely to cause problems, especially if you have lots of posts (or very large ones) in your database.

I have increased memory to 32MB (was 16), but its the same. (Allowed memory size of 33554432 bytes exhausted (tried to allocate 20 bytes))

Important thing is that it crashes on first time i want to access database. And does not come even to data.

Call stack looks something like that (calling method)…




1. Post::__model()__->FindAll();


2. 	public static function model($className=__CLASS__)

	{

		if(isset(self::$_models[$className]))

			return self::$_models[$className];

		else

		{

			$model=self::$_models[$className]=new $className(null);

			$model->attachBehaviors($model->behaviors());

			__$model->_md=new CActiveRecordMetaData($model);__

			return $model;

		}

	}


3. public function __construct($model)

	{

		$this->_model=$model;


		$tableName=$model->tableName();

		if(($table=$model->getDbConnection()->getSchema()->__getTable($tableName)__)===null)

			throw new CDbException(Yii::t('yii','The table "{table}" for active record class "{class}" cannot be found in the database.',

				array('{class}'=>get_class($model),'{table}'=>$tableName)));

		if($table->primaryKey===null)

			$table->primaryKey=$model->primaryKey();

		.........

		}

	}


4. 	public function getTable($name)

	{

		if(isset($this->_tables[$name]))

			return $this->_tables[$name];

		else if(!isset($this->_cacheExclude[$name]) && ($duration=$this->_connection->schemaCachingDuration)>0 && ($cache=Yii::app()->getCache())!==null)

		{

			$key='yii:dbschema'.$this->_connection->connectionString.':'.$this->_connection->username.':'.$name;

			if(($table=$cache->get($key))===false)

			{

				$table=$this->createTable($name);

				$cache->set($key,$table,$duration);

			}

			return $this->_tables[$name]=$table;

		}

		else

			return $this->_tables[$name]=$this->__createTable($name)__;

	}


5.	protected function createTable($name)

	{

		$table=new CMysqlTableSchema;

		$this->resolveTableNames($table,$name);


		if($this->findColumns($table)) // <-- First call with similar query (works)

		{

			$this->__findConstraints($table)__;

			return $table;

		}

		else

			return null;

	}


6.       protected function findConstraints($table)

	{

		$row=$this->getDbConnection()->createCommand('SHOW CREATE TABLE '.$table->rawName)->__queryRow()__;

		$matches=array();

		......

	}


7. public function queryRow($fetchAssociative=true)

	{

		return $this->queryInternal('fetch',$fetchAssociative ? PDO::FETCH_ASSOC : PDO::FETCH_NUM);

	}


8. private function queryInternal($method,$mode)

	{

		$params=$this->_connection->enableParamLogging && !empty($this->_params) ? '. Bind with parameter ' . implode(', ',$this->_params) : '';

		Yii::trace('Querying SQL: '.$this->getText().$params,'system.db.CDbCommand');

		try

		{

			if($this->_connection->enableProfiling)

				Yii::beginProfile('system.db.CDbCommand.query('.$this->getText().')','system.db.CDbCommand.query');


			if($this->_statement instanceof PDOStatement)

				$this->_statement->execute();

			else

				$this->_statement=$this->getConnection()->getPdoInstance()->__query($this->getText())__; // BOOM


			if($method==='')

				$result=new CDbDataReader($this);

			else

			{

				$result=$this->_statement->{$method}($mode);

				$this->_statement->closeCursor();

			}


			.......

	}



And this happened after you moved the application? No other changes?

I just tried to recreate it, but without luck. Can you debug to this location and confirm it happens at first invocation of "SHOW CREATE TABLE table" to ensure it isn’t a problem with an infinite loop and endless calls to findAll()? By the way: The statement isn’t "SHOW CREATE TABLE table" literally, is it?

If it is really a problem that occurs during the first call of this statement, can you reproduce the error with a plain php script that doesn’t use yii (only create pdo object and run query)?

You can also enable db profiling in the config, maybe that tells you more:




    'log'=>array(

      'class'=>'CLogRouter',

      'routes'=>array(

        /* Log everything right into the browser (for development) */

        array(

          'class'=>'CWebLogRoute',

          'levels'=>'error, warning, profile, info, trace',

        ),

        /* Log everything right into the browser (for development) */

        array(

          'class'=>'CProfileLogRoute',

          'report'=>'summary',  /* summary or callstack */

        ),

      ),

    ),

    'db'=>array(

      'class'=>'CDbConnection',

      'connectionString'=>'...',

      'username'=>'...',

      'password'=>'*****',

      'charset'=>'UTF8',

      'emulatePrepare'=>true,

      'enableProfiling'=>true,

    ),



I once had the problem of this happening when the my application threw an error and then a customer error handler was invoked which that used debug_backtrace. It seems like debug_backtrace sometimes uses up a huge amount of memory.

Maybe you wanna check for that.

Finally I have solved the problem:

Real error on that call is something like: SQLSTATE[HY000]: General error: 2030 This command is not supported in the prepared statement protocol yet

I find out, that MySQL 5.0 causes this error. So I have upgraded to MySQL 5.1, and that solved the problem.

Thank everybody for answers :)

Mh, interesting. May I ask if you enabled emulatePrepare when this error appeared?

No i haven’t, because it crashed also. I think, because I have had a problem with ~CDbMessage table names (incorrect cases). Real error was catched on catch() section whitch i have missed, and framework were trying to show me error message, but with incorrect table names in multilanguage calsses it crashed with out of memory error…

I think you can config "allowed memory exhousted" in your hosting ( httpconf, php.ini)