Función MySQL en el script de instalación
-
13-12-2019 - |
Pregunta
¿Es posible crear una función desde un script de instalación de Magento?Actualmente tengo el siguiente 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;
");
Pero me lanzan una excepción 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
- no es muy útil.
Para que esto se ejecute en PHPMyAdmin, tuve que agregar líneas sobre DELIMITADORES, pero creo que eso es un inconveniente de la GUI en lugar de la FUNCIÓN que los requiere.Si los incluyo, obtengo una excepción al definir un 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 ;
");
Error: 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)
Solución
Mage_Core_Model_Resource_Setup::run()
acepta múltiples consultas, dividiendo el argumento dado (declaración SQL) en punto y coma.Esto lleva a que el cuerpo de la función se divida en múltiples llamadas separadas.Entonces, la declaración de la función está incompleta y la creación de la función falla con el mensaje de excepción proporcionado.
Además, a diferencia de utilizar el cliente CLI de MySQL (o PHPMyAdmin) directamente, definir un delimitador conduce a un PDOException
. Nils Preuß recibió una solución del Lista de correo de Zend_Db Hace unos pocos años:
- No te preocupes por DELIMITER, no lo necesitas.
- Debe SOLTAR y CREAR en dos declaraciones separadas.
- Omita el método de consulta ZF predeterminado.
En resumen, el siguiente fragmento conducirá a la creación de la función:
$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;
");