Perl DBI execute not maintaining MySQL stored procedure results - mysql

I'm having a problem with executing a stored procedure from Perl (using the DBI Module). If I execute a simple SELECT * FROM table there are no problems.
The SQL code is:
DROP FUNCTION IF EXISTS update_current_stock_price;
DELIMITER |
CREATE FUNCTION update_current_stock_price (symbolIN VARCHAR(20), nameIN VARCHAR(150), currentPriceIN DECIMAL(10,2), currentPriceTimeIN DATETIME)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE outID INT;
SELECT `id` INTO outID FROM `mydb449`.`app_stocks` WHERE `symbol` = symbolIN;
IF outID > 0 THEN
UPDATE `mydb449`.`app_stocks`
SET `currentPrice` = currentPriceIN, `currentPriceTime` = currentPriceTimeIN
WHERE `id` = outID;
ELSE
INSERT INTO `mydb449`.`app_stocks`
(`symbol`, `name`, `currentPrice`, `currentPriceTime`)
VALUES (symbolIN, nameIN, currentPriceIN, currentPriceTimeIN);
SELECT LAST_INSERT_ID() INTO outID;
END IF;
RETURN outID;
END|
DELIMITER ;
The Perl code:
$sql = "select update_current_stock_price('$csv_result[0]', '$csv_result[1]', '$csv_result[2]', '$currentDateTime') as `id`;";
My::Extra::StandardLog("SQL being used: ".$sql);
my $query_handle = $dbh->prepare($sql);
$query_handle->execute();
$query_handle->bind_columns(\$returnID);
$query_handle->fetch();
If I execute select update_current_stock_price('aapl', 'Apple Corp', '264.4', '2010-03-17 00:00:00') asid; using the mysql CLI client it executes the stored function correctly and returns an existing ID, or the new ID.
However, the Perl will only return a new ID, (incrementing by 1 on each run). It also doesn't store the result in the database. It looks like it's executing a DELETE on the new id just after the update_current_stock_price function is run.
Any help? Does Perl do anything funky to procedures I should know about?
Before you ask, I don't have access to binary logging, sorry.

Perhaps you're doing it in a transaction and it's getting rolled back? The row is inserted but never becomes committed and cannot be seen.
I'd try it on your dev server and enable general query log, if in doubt.
Also you may want to know about the INSERT ... ON DUPLICATE KEY UPDATE syntax, which can probably do what you're trying to do anyway.

try
$query_handle->dump_results(15, "\n", '|');
before the bind_columns call to see if it is actually getting the results back, you could also try replace SELECT storedprocedure with SELECT * FROM storedprocedure

You should check that you are running the latest version of DBD::mysql (which is the MySQL-driver used by DBI). There used to be several issues with stored procedures, at least some are fixed in recent versions. Maybe these ressources are also helpful:
http://www.perlmonks.org/?node_id=609098
http://www.perlmonks.org/?node_id=830585

Related

SQL Event - DELETE AND UPDATE rows on tables after UPDATE other table

I'd like to have a tricky SQL statement as an Event that runs every couple of minutes.
Currently, I'm doing so with Java, using 3 separate statements that executing sequentiality in a transaction connection.
Q: I don't know how to construct such an SQL statement without Java. If impossible to have a single SQL statement, I'd like to use transaction (as I'm using in Java) and rollback in case of failure in any of those separate statements.
My Case:
I have 3 tables: "Factory", "Plan", "Machine".
I want to do something as below:
1.
WHERE Machines.annualCheck == "TRUE"
SET Machine.status = "IN_ANNUAL_CHECK"
For machines that got updated I need to do the following:
2.1 Update the related factory
WHERE Factory.id == Machine.linkFactoryID
UPDATE Factory.totalActiveMachines = --1
2.2 Delete the upcoming plans that planned to be handled by the related machine
DELETE rows WHERE Plan.willHandleByMachineID = Machine.ID
p.s. I'm using MySQL
Thank you!
Update:
In following to Simonare suggestion, I tired to do the following:
DELIMITER $
CREATE PROCEDURE annualCheck(IN Machine_ID int, IN Factory_ID int)
BEGIN
UPDATE machine_table
SET machine_table.annualCheck = 'IN_ANNUAL_CHECK'
WHERE machine_table.machine_id = Machine_ID;
UPDATE factory_table
SET factory_table.totalActiveMachines = factory_table.totalActiveMachines - 1
WHERE factory_table.factory_id = Factory_ID;
DELETE FROM plan_table WHERE plan_table.assign_to_machine = Machine_ID
END$
DELIMITER $$
BEGIN
SELECT #m_id = machine_id, #f_id = link_factory_id
FROM machine_table
WHERE machine_table.annualCheck = 'TRUE';
END$$
CALL annualCheck(#m_id,#f_id)
I don't know why, but I'm running into syntax errors - one after the other.
It's my first time to use PROCEDURE and DELIMITER. Am I doing it right?
you can use stored procedure
delimiter //
CREATE PROCEDURE myProc (IN Machine_ID int)
BEGIN
UPDATE myTable
SET Machine.status = "IN_ANNUAL_CHECK"
WHERE Machines.annualCheck == "TRUE";
Update the related factory
WHERE Factory.id == Machine.linkFactoryID
UPDATE Factory.totalActiveMachines = totalActiveMachines -1;
DELETE FROM Plan WHERE Plan.willHandleByMachineID = Machine_ID;
END//
then you can execute it either from mysql
CALL simpleproc(#a);
or from Java
It is also possible to create trigger on the Machine table, something like this:
CREATE TRIGGER `TRG_Machines_AfterUpdate` AFTER UPDATE ON `Machine` FOR EACH ROW BEGIN
IF OLD.annualCheck = 'TRUE' AND NEW.annualCheck = 'IN_ANNUAL_CHECK' THEN
UPDATE
Factory
SET
totalActiveMachines = totalActiveMachines - 1
WHERE
id = NEW.linkFactoryID
;
DELETE FROM
Plan
WHERE
willHandleByMachineID = NEW.ID
;
END;
END
So you can just issue normal update:
UPDATE Machine SET annualCheck = 'IN_ANNUAL_CHECK' WHERE annualCheck = 'TRUE'

call simple database procedure using Slick 3.0

I have written a simple database procedure in mySQL as follows:
DROP PROCEDURE IF EXISTS sp_doSomething;
DELIMITER //
CREATE PROCEDURE sp_doSomething
(IN pVal1 varchar(100),
IN pVal2 int(15)
)
BEGIN
DECLARE vCnt int(5) DEFAULT 0;
DECLARE vID int(15) DEFAULT 0;
DECLARE vTempID int(15) DEFAULT 0;
-- get ID
SELECT id INTO vID FROM T1
WHERE name = pVal1;
-- get count
SELECT count(*) INTO vCnt FROM T1
WHERE owner = vID;
-- get the log
INSERT INTO log select CONCAT('-v1-:', pVal1, ':-v2-:', pVal2);
-- Create basic stuff if it doesn't exist
IF vFolderCnt = 0 THEN
INSERT INTO T1 (`id`, `col1`, `col2`, `col3`)
SELECT null, vID, 'some value', CONCAT(vID,'^1') FROM T1
WHERE owner = 0;
END IF;
commit;
END //
DELIMITER ;
Now, I want to call this procedure in my Play Framework 2.4 application which uses Slick 3.0. It is such a simple thing but I am really struggling with it as there is no proper documentation available. It's very frustrating.
As it's mentioned on Google Group here https://groups.google.com/forum/#!searchin/scalaquery/procedure/scalaquery/BUB2-ryR0bY/EFZGX663tRYJ
I tried calling the procedure by different way. The code compiles but the procedure does not get called at all.
This statement gives an action error.
db.run(sql"{call sp_doSomething('${st.val1}', 1)}")
The following statement compiles fine but does not invoke the procedure.
db.run(sql"{call sp_doSomething('${st.val1}', 1)}".as[Int])
The following statement compiles fine but does not invoke the procedure.
db.run(sqlu"{call sp_doSomething('${st.val1}', 1)}")
Or
db.run(sqlu"{?=call sp_doSomething('${st.val1}', 1)}")
I have granted the Execute permission on the procedure to my DB user and verified it.
Also, I am not sure, whether the COMMIT is required in the procedure or not?
Any help, will be highly appreciated.
I have managed to invoke the stored procedure using old prepareCall method. Here's how I have done it. Hope, it might help someone.
db.withSession {
implicit session => {
val cs = session.conn.prepareCall("{call sp_doSomething(?, ?)}")
cs.setString(1, st.val1)
cs.setLong(2, 1L)
val result = cs.executeUpdate()
}
}
But I would be still interested in invoking the procedure using sql"" or sqlu"".
For me the following works in Slick 3.2:
delimiter //
create procedure Try1()
begin
select userid from TBL_USER where id = "4";
end //
delimiter ;
Then
def runProcByRawSql() : Future[Vector[String]] = {
def runproc = sql"""call Try1()""".as[String]
db.run(runproc)
}

Third-party stored procedure returns value on select and it stops my own stored procedure

I'm designing a Stored Procedure which does a lot of things, some of them covered for third-party SPs that I cannot edit because they're hugely used on other places of the app I'm developing. I'll simplify my code in order to explain my problem a little easier:
My code is the following:
DELIMITER ;;
CREATE PROCEDURE `my_own_sp`(
IN my_param INT(11),
OUT my_returned_value INT(11),
OUT logger TEXT
)
BEGIN
SET logger = "echo off";
CALL third_party_SP(my_param);
SET logger = "half way!";
CALL another_third_party_SP(my_param);
SELECT id_user INTO my_returned_value FROM main_Table WHERE id_param = my_param;
SET logger = "This is the end...";
END;;
DELIMITER ;
both third party SPs would be like the following, they don't return any value but they modify some tables and records and then they make a SELECT in order to receive the result in PHP:
DELIMITER ;;
CREATE PROCEDURE `third_party_SP`(
IN my_param INT(11)
)
BEGIN
-- Do a lot of magic between tables
SELECT * FROM secondary_table WHERE id_param = my_param;
END;;
DELIMITER ;
But when I execute my SP, instead of receiving the value of my_returned_param and logger = "This is the end...", I receive the select of third_party_SP (I'm not even receiving logger = "half way!". It seems to me that the execution of my_own_sp stops once it receives a returned value, but this value is the last select of third_party_SP.
So the question is: can I handle the returned select of third_party_SP so I can keep working? or maybe there's another way to call third_party_SP in order to avoid the returned select?
Thank you very very much

MySQL - Stored Proc creation in code giving syntax error

I'm baffled by the syntax error I keep getting in MYSQL (ver 5.2) when executing CREATE PROC in code.
The MySQL Proc code:
DELIMITER //
CREATE PROCEDURE Delete_BillOfMaterialsDetail
(IN InOrderDate DATE,
IN InProductCode varchar(40),
IN InRawMaterialProductCode varchar(40)
)
BEGIN
IF EXISTS
(SELECT * FROM basf_rawmaterialplanning.BillOfMaterialsDetail
WHERE OrderDate = InOrderDate
and ProductCode = InProductCode
and RawMaterialProductCode = InRawMaterialProductCode)
THEN
DELETE FROM basf_rawmaterialplanning.BillOfMaterialsDetail
WHERE OrderDate = InOrderDate
AND ProductCode = InProductCode
AND RawMaterialProductCode = InRawMaterialProductCode;
END IF;
END //
DELIMITER ;
I build it using a string datatype then execute it against the DB which gives a syntax error.
I'm not to sure what I'm doing wrong?
Thanks Guys i figured it out, will post the answer as so as StackOverflow allows me to
Just execute the command for changing delimiter separately and then execute the stored procedure create command.
The system is currently considering it to be one single command and hence the error :)
Try this code -
CREATE PROCEDURE Delete_BillOfMaterialsDetail3(
IN InOrderDate DATE,
IN InProductCode varchar(40),
IN InRawMaterialProductCode varchar(40))
DELETE FROM basf_rawmaterialplanning.BillOfMaterialsDetail
WHERE OrderDate = InOrderDate
AND ProductCode = InProductCode
AND RawMaterialProductCode = InRawMaterialProductCode;
Thanks Guys, finally figured it out
I added my script in the MySqlScript object and executed using that class, works 100% without any syntax errors

Weird issue with a stored procedure in MySQL

I need to add a new stored procedure on our company's MySQL server. Since it's just slightly different, I used an already existing one, added the additional field and changed the name of the procedure. The weird thing now is that when I want to execute the statement, it returns:
Error Code: 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 3
reffering to the 0 in this line: SET #update_id := 0; What makes it weird is, that I queried that stored procedure by using SHOW CREATE PROCEDURE . It's saved in our database and is working fine. I just can't use it as a new stored procedure (no matter if I try to apply it to the new test database or if I use it on the existing database by giving it a new name).
I searched the internet for a solution. Unfortunately to no avail. I even set up a new database with a new table and some demo values where I tried to execute the original, unaltered stored procedure. It returns the exact same error.
Here's the currently used and working stored procedure I'm talking about:
CREATE DEFINER=`root`#`localhost` PROCEDURE `customer_getcard`(IN Iinstance INT, IN Itimebuy DOUBLE, IN Iprice DECIMAL(10,2), IN Itariff INT, IN Icomment VARCHAR(128))
BEGIN
SET #update_id := 0;
UPDATE customer_shop SET state = 1, id = (SELECT #update_id := id), instance=Iinstance, timebuy=Itimebuy, price=Iprice, comment=Icomment WHERE tariff=Itariff AND state = 0 LIMIT 1;
SELECT * FROM customer_shop WHERE id = #update_id;
END
I hope you guys can help me as I am completely out of ideas what's wrong. :/
Regards, Mark
You need to define an alternative command delimiter, as MySQL currently thinks your CREATE PROCEDURE command ends at the first ; it encounters (on line 3, after the 0), which would be a syntax error as it's after a BEGIN but before the corresponding END:
DELIMITER ;; -- or anything else you like
CREATE PROCEDURE
...
END;; -- use the new delimiter you chose above here
DELIMITER ; -- reset to normal
MySQL stored procedures do not use ":=" for value assignment, just use "=".
Also don't think "id = (SELECT #update_id := id)" is acceptable. Here's an alternative solution (untested):
CREATE DEFINER=`root`#`localhost` PROCEDURE `customer_getcard`(IN Iinstance INT, IN Itimebuy DOUBLE, IN Iprice DECIMAL(10,2), IN Itariff INT, IN Icomment VARCHAR(128))
BEGIN
select id into #update_id from customer_shop WHERE tariff=Itariff AND state = 0 LIMIT 1;
UPDATE customer_shop SET state = 1, instance=Iinstance, timebuy=Itimebuy, price=Iprice, comment=Icomment where id = #update_id;
SELECT * FROM customer_shop WHERE id = #update_id;
END
You may also want to put error handlers in case there's no matching row to be edited.