→

Фреймворки →  Zend DB съедает память

Бывает, так, что валится ошибка и нужно быть телепатом, что бы продетектить эту ошибку. Так было и в этот раз.

При попытке забрать данные при помощи fetch, fetchAll, fetch*, find, findParentRow и т.д… выдает ошибку.

Fatal error: Out of memory (allocated 12058624) (tried to allocate 4294967294 bytes)


То, что это Zend_DB стало понятно немного позже. Zend_DB некорректно работает с типами LONGTEXT И LONGBLOB и эту проблему разработчики zend framework еще не решили. При формировании sql запроса Zend_DB смотрит на типы полей таблицы и пытается выделить память под будущей массив записей для каждой ячейки таблицы в соответствии с ее максимальным размером.

Для справки, размер LONGTEXT 4GB (2 в степени 32 – 1) символов т.е. даже, если размеры ваше таблицы не превышают 10kb, но в ней есть злостное поле LONGTEXT или LONGBLOB, то скорее будет хана.

Рецепт лечения простой — LONGTEXT меняем на MEDIUMTEXT (его размер 16Mb), а еще лучше на varchar(64000), но это совсем другая история:)

Для неверующих и читающих на английском http://framework.zend.com/issues/browse/ZF-1498
2
4

MySQL →  Решение ошибки MySql 1442

Итак, имеем ошибку MySql 1442

Для рассмотрения проблемы в полевых условиях создадим таблицу:
CREATE TABLE `t1` (
`a` char(1) default NULL,
`b` smallint(6) default NULL
);
insert into t1 values ('y','1');

Она содержит поля a и b. Необходимо проапдейтить поле a до какого-то 'n', когда b = 0.
Решение 1:
DELIMITER |
CREATE TRIGGER trigger1 AFTER UPDATE ON t1
FOR EACH ROW UPDATE t1 SET a= 'n' WHERE b=0;
|
DELIMITER ;

Тригер создается на ура, но мы получаем сабжевую ошибку MySql 1442
Can’t update table ‘t1′ in stored function/trigger because it is already used by statement which invoked this stored function/trigger
когда пытаемся заапдейтить поле b в таблице t1.
mysql> update t1 set b=0;
ERROR 1442 (HY000): Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

Как мы уже поняли, дело в нашем тригере. Для решения проблемы, нам необходимо его переписать следующим образом:
drop trigger trigger1;
DELIMITER |
CREATE TRIGGER trigger1 BEFORE UPDATE ON t1
FOR EACH ROW
BEGIN
IF NEW.b=0 THEN
SET NEW.a = 'n';
END IF;
END
|
DELIMITER ;

С новым тригером ошибка вида «ERROR 1442 (HY000): Can’t update table ‘t1′ in stored function/trigger because it is already used by statement which invoked this stored function/trigger.» уже не вознимает при апдейте. Проверим?
mysql> update t1 set b=0;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t1\G
*************************** 1. row ***************************
a: n
b: 0

Таким образом, если мы хотим создать тригер на таблицу, которая будет апдейтись себя по изменению на свои же поля, то нам необходимо использовать поле NEW.column_name, которое будет ссылаться на строку после апдейта и не делать полного апдейта.

Если же вы будете апдейтить другую таблицу, то первое решение вполне подойдет:
DELIMITER |
CREATE TRIGGER trigger1 AFTER UPDATE ON t1
FOR EACH ROW UPDATE t2 SET a= ‘n’ WHERE b=0;
|
DELIMITER ;
0