Lenguajes:
PHP, PL/SQL
Problema:
No consigo que se ejecute ningún procedimiento PL/SQL almacenado desde mi script PHP.
Códigos:
Tablas:
/*GOODS TABLE, WILL CONTAIN ALL GOODS*/
CREATE TABLE GOODS(
ID INT(3) AUTO_INCREMENT,
NAME CHAR(20) UNIQUE,
IMGFILE CHAR(20),
L_PRICE INT(4),
S_PRICE INT(4),
H_PRICE INT(4),
C_PRICE INT(4),
PRIMARY KEY(ID));
/*TRADERS TABLE, WILL CONTAIN ALL USERS AND THEIR DATA*/
CREATE TABLE TRADERS(
ID INT(3) AUTO_INCREMENT,
USERNAME CHAR(20) NOT NULL,
PASSWORD CHAR(20) NOT NULL,
MAIL CHAR(40) NOT NULL,
CREDITS CHAR(20) NOT NULL,
PRIMARY KEY(ID));
/*STOCKS TABLE, WILL CONTAIN EACH USER'S (TRADER) STOCK*/
CREATE TABLE STOCKS(
GOOD_ID INT(3),
TRADER_ID INT(3),
AMMOUNT INT(10),
AVG_BUY INT(4),
FOREIGN KEY(GOOD_ID)
REFERENCES GOODS(ID)
ON DELETE CASCADE,
FOREIGN KEY(TRADER_ID)
REFERENCES TRADERS(ID)
ON DELETE CASCADE);
Procedimiento Almacenado a llamar:
/*THIS PROCEDURE ALLOWS THE TRADERS TO BUY STOCKS*/
CREATE PROCEDURE BUY_STOCK(P_GOOD INT,P_TRADER INT,P_AMMOUNT INT)
BEGIN
DECLARE V_PRICE, V_COST INT;
SELECT C_PRICE INTO V_PRICE
FROM GOODS
WHERE ID = P_GOOD;
SET V_COST = V_PRICE*P_AMMOUNT;
IF HAS_CREDITS(P_TRADER,V_COST) THEN
IF HAS_STOCK(P_GOOD,P_TRADER) THEN
UPDATE STOCKS
SET AMMOUNT = AMMOUNT + P_AMMOUNT
WHERE GOOD_ID = P_GOOD
AND TRADER_ID = P_TRADER;
UPDATE STOCKS
SET AVG_BUY = ((AVG_BUY*(AMMOUNT-P_AMMOUNT))+(V_PRICE*P_AMMOUNT))/AMMOUNT
WHERE GOOD_ID = P_GOOD
AND TRADER_ID = P_TRADER;
ELSE
INSERT INTO STOCKS
VALUES(P_GOOD,P_TRADER,P_AMMOUNT,V_PRICE);
END IF;
UPDATE TRADERS
SET CREDITS = CREDITS - V_COST
WHERE ID = P_TRADER;
END IF;
END;
Código PHP que trata de llamar al procedimiento almacenado:
<?php
session_name('trademaster');
session_start();
if($_POST['transaction'] = "Buy")
{
$good = $_POST['goodid'];
$id = $_SESSION['id'];
$ammount = $_SESSION['ammount'];
$db = new PDO("mysql:host=localhost;dbname=trademaster", 'trader', '********');
$x = $db->prepare('CALL BUY_STOCK(:good, :trader, :ammount)');
$x->bindValue(':good', $good, PDO::PARAM_INT);
$x->bindValue(':trader', $id, PDO::PARAM_INT);
$x->bindValue(':ammount', $ammount, PDO::PARAM_INT);
$x->execute();
unset($db);
header("location:stocks.php");
exit();
}
?>
Error:
PDOStatement::execute(): SQLSTATE[42000]: Syntax error or access violation: 1370 execute command denied to user 'trader'@'localhost' for routine 'trademaster.BUY_STOCK'
Observaciones:
El usuario 'trader'@'localhost' que interactúa con la base de datos tiene los permisos de USAGE, SELECT, INSERT, UPDATE, DELETE y EXECUTE sobre todas las tablas de la base de datos (trademaster.*).
Queries hacia la base de datos con SELECT, INSERT y UPDATE funcionan.
El procedimiento almacenado funciona correctamente, ya lo he probado localmente desde una consola MySQL.
La password del objeto PDO la quité por razones evidentes.
Los valores POST y SESSION se recogen adecuadamente, lo he comprobado.
Realmente no veo el problema xD
Segun lecturas en SOF podrías probar..
- Meterte como root y
GRANT EXECUTE ON PROCEDURE trademaster.BUY_STOCK TO 'trader'@'localhost'
o cambiar PROCEDURE por FUNCTION.
Saludos
Olvidé mencionar que probé a utilizar como usuario root en el PHP para ver si era cosa de permisos. Y me devolvía el mismo error...
De todas formas, voy a probar a ver si tira poniendo el permiso en específico para los procedimientos almacenados...
Teniendo en cuenta que tengo 2 procedimientos que usan unas 2-3 funciones cada uno... ¿tendría que dar permisos de esta manera individual para cada función/procedimiento)?
--
EDIT: He probado, sigue sin funcionar dando los permisos específicos.
Utiliza comillas dobles y prueba..
$x = $db->prepare("CALL BUY_STOCK(:good, :trader, :ammount)");
Nada, lo mismo con comillas simples que comillas dobles. No hace nada y sigue devolviendo el mismo error.
Nota: En las demás consultas que no son llamadas (SELECT, INSERT, UPDATE y DELETE) uso comilla simple y funciona y también estoy metiendo parámetros.
Tiene pinta de que hay algún error de sintaxis en la cadena que se manda finalmente al servidor.
Curiosamente, si hago var_dump de $x me devuelve un valor tal que:
'CALL BUY_STOCK(:good, :trader, :ammount)'
Si hago un var_dump de un código similar hecho con MySQLI, devuelve:
'CALL BUY_STOCK(1,1,10)'
(que son los valores de las variables a las que hago Bind).
Si la operación la hago de la siguiente forma:
$x = $db->prepare('CALL BUY_STOCK(?,?,?)');
$x->bindParam(1, $good, PDO::PARAM_INT);
$x->bindParam(2, $id, PDO::PARAM_INT);
$x->bindParam(3, $ammount, PDO::PARAM_INT);
Lo que me devuelve var_dump es:
'CALL BUY_STOCK(?,?,?)'
Desgraciadamente, en todos estos casos, no funciona.
¿Qué puede estar mal o quedándose en el tintero?
Al final he portado todo lo que tenía en PL a PHP.
Desgraciadamente, me surgió un nuevo problema con la base de datos. Voy a abrir un topic al respecto.
Quiero probar intentar encontrar el problema.. en version de mysql estas trabajando ?
Si te vuelve a generar problemas con GRANT y REVOKE, explica un poco que fue lo que hiciste u el error.
Tiene pinta de que se le había corrompido algo, ya que reinstalar y volcar tablas, users y privilegios tal y como estaban al empezar todo funciona bien.
De todas formas, de volver a fallar, comento.