Função MySQL no script do instalador
-
13-12-2019 - |
Pergunta
É possível criar uma função a partir de um script de instalação do Magento?Atualmente tenho o seguinte código:
$installer = $this;
$installer->startSetup();
$installer->run("
DROP function IF EXISTS {$this->getTable('getLatestActivity')};
CREATE FUNCTION {$this->getTable('getLatestActivity')} (activityid int) RETURNS int(11)
BEGIN
set @rank = 0;
set @matchingId := (select id from (
SELECT @rank := @rank+1 AS rank, t_act.id, t_act.date
FROM activityupdates ut_act
LEFT JOIN activityupdates AS t_act ON t_act.ticked = 1
AND t_act.date <= ut_act.date AND t_act.customer_id = ut_act.customer_id AND t_act.type = ut_act.type
WHERE ut_act.id = activityid
ORDER BY t_act.date DESC
)ranked
where ranked.rank = 1);
return @matchingId;
END;
");
Mas recebo uma exceção lançada SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 4
- não é muito útil.
Para fazer isso funcionar no PHPMyAdmin, tive que adicionar linhas relacionadas a DELIMITERS, mas acho que isso é uma desvantagem da GUI, e não da FUNCTION que as exige.Se eu incluí-los, recebo apenas uma exceção sobre a definição de um DELIMITER.
$installer->run("
DROP function IF EXISTS `{$this->getTable('getLatestActivity')}`;
DELIMITER $$
CREATE FUNCTION `{$this->getTable('getLatestActivity')}` (activityid int) RETURNS int(11)
BEGIN
set @rank = 0;
set @matchingId := (select id from (
SELECT @rank := @rank+1 AS rank, t_act.id, t_act.date
FROM activityupdates ut_act
LEFT JOIN activityupdates AS t_act ON t_act.ticked = 1
AND t_act.date <= ut_act.date AND t_act.customer_id = ut_act.customer_id AND t_act.type = ut_act.type
WHERE ut_act.id = activityid
ORDER BY t_act.date DESC
)ranked
where ranked.rank = 1);
return @matchingId;
END$$
DELIMITER ;
");
Erro: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER $$ CREATE FUNCTION getLatestActivity (activityid int)
Solução
Mage_Core_Model_Resource_Setup::run()
aceita múltiplas consultas, dividindo o argumento fornecido (instrução SQL) em ponto e vírgula.Isso faz com que o corpo da função seja dividido em várias chamadas separadas.A declaração da função fica incompleta e a criação da função falha com a mensagem de exceção fornecida.
Além disso, ao contrário de usar o cliente MySQL CLI (ou PHPMyAdmin) diretamente, definir um delimitador leva a um PDOException
. Nils Preuss recebeu uma solução do Lista de discussão Zend_Db alguns anos atrás:
- Não se preocupe com DELIMITER, você não precisa dele.
- Você deve DROP e CREATE em duas instruções separadas.
- Ignore o método de consulta padrão do ZF.
Resumindo, o seguinte trecho levará à criação da função:
$this->getConnection()->query("DROP function IF EXISTS `{$this->getTable('getLatestActivity')}`");
$this->getConnection()->query("
CREATE FUNCTION `{$this->getTable('getLatestActivity')}` (activityid int) RETURNS int(11)
BEGIN
set @rank = 0;
set @matchingId := (select id from (
SELECT @rank := @rank+1 AS rank, t_act.id, t_act.date
FROM activityupdates ut_act
LEFT JOIN activityupdates AS t_act ON t_act.ticked = 1
AND t_act.date <= ut_act.date
AND t_act.customer_id = ut_act.customer_id
AND t_act.type = ut_act.type
WHERE ut_act.id = activityid
ORDER BY t_act.date DESC
) ranked
where ranked.rank = 1);
return @matchingId;
END;
");