Llamar un procedimiento almacenado PL desde PHP.

Iniciado por Saberuneko, 19 Marzo 2014, 16:57 PM

0 Miembros y 1 Visitante están viendo este tema.

Saberuneko

Lenguajes:
PHP, PL/SQL
Problema:
No consigo que se ejecute ningún procedimiento PL/SQL almacenado desde mi script PHP.
Códigos:

Tablas:
Código (sql) [Seleccionar]
/*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:
Código (sql) [Seleccionar]
/*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:
Código (php) [Seleccionar]
<?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'$goodPDO::PARAM_INT);
$x->bindValue(':trader'$idPDO::PARAM_INT);
$x->bindValue(':ammount'$ammountPDO::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.

#!drvy

Realmente no veo el problema xD

Segun lecturas en SOF podrías probar..

- Meterte como root y

Código (sql) [Seleccionar]
GRANT EXECUTE ON PROCEDURE trademaster.BUY_STOCK TO 'trader'@'localhost'

o cambiar PROCEDURE por FUNCTION.


Saludos


Saberuneko

#2
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.

EFEX

Utiliza comillas dobles y prueba..

Código (php) [Seleccionar]

$x = $db->prepare("CALL BUY_STOCK(:good, :trader, :ammount)");
GITHUB 

Saberuneko

#4
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:

Código (php) [Seleccionar]

$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?

Saberuneko

#5
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.

EFEX

#6
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.
GITHUB 

Saberuneko

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.