I'm using the SQL Server Driver for PHP to connect to an SQL Server 2008 Express. Right now, I'm trying to replace all SELECT, UPDATE and INSERT statements by stored procedures. This is working fine for SPs that just contain a SELECT statement. But now I tried to do one with an update, and I keep getting the error message "Executing SQL directly; no cursor.". I can call the SP fine from Management Studio with the same parameter values.
Any ideas?
Cheers
Alex
EDIT: here's one update procedure. The funny part is, the procedure is actually executed fine and updates the data like it's supposed to. But it still returns an error, resulting in an exception.
First, the PHP code that fails:
if (! $this->Result = sqlsrv_query($this->Conn, $strQuery, $arrParameters, array("Scrollable"=>SQLSRV_CURSOR_STATIC)))
{
$this->sendErrorMail($strQuery, $arrParameters);
throw new Exception(4001);
}
SQL
USE [testsite]
GO
/****** Object: StoredProcedure [dbo].[Items_countDownload] Script Date: 09/09/2010 18:03:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Alexis Hildebrandt
-- Create date: 2010-09-09
-- Description: Increases the download count by 1
-- =============================================
ALTER PROCEDURE [dbo].[Items_countDownload]
#Id INT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #DownloadCount INT = 0, #MaxCount INT = 0, #Id2 INT = 0
DECLARE itemCursor CURSOR SCROLL
FOR
SELECT Id, Downloads
FROM Items
WHERE Id = #Id
OR SKU IN
(
SELECT SKU FROM Items WHERE Id = #Id
)
FOR UPDATE OF Downloads
OPEN itemCursor
FETCH NEXT FROM itemCursor
INTO #Id, #DownloadCount;
-- Find the largest Download count across all versions of the item
WHILE ##FETCH_STATUS = 0
BEGIN
IF #MaxCount < #DownloadCount
SET #MaxCount = #DownloadCount;
FETCH NEXT FROM itemCursor
INTO #Id, #DownloadCount;
END
-- Increase the download count by one for all versions
FETCH FIRST FROM itemCursor
INTO #Id, #DownloadCount;
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE Items
SET Downloads = #MaxCount + 1
WHERE CURRENT OF itemCursor
FETCH NEXT FROM itemCursor
INTO #Id, #DownloadCount;
END
CLOSE itemCursor;
DEALLOCATE itemCursor;
END
look into the permissions: Executing SQL directly; no cursor
Try removing "Scrollable"=>SQLSRV_CURSOR_STATIC option from the call. The procedure you're calling doesn't return any open cursors to PHP code.
Related
I have spent hours trying to get to the bottom of this and it is driving me la la.
I have a simple stored procedure that just inputs 10,000 rows into a table. This is done because it takes long enough to prove the point (about 12 seconds).
create table lala (id int not null identity(1,1), txt varchar(100))
go
CREATE PROCEDURE lalatest
AS
BEGIN
DECLARE #x int;
SET #x = 10000;
WHILE #x > 0
BEGIN
INSERT INTO lala (txt) VALUES ('blah ' + CAST(#x AS varchar(10)));
SET #x = #x - 1;
END;
END;
When I run the stored procedure from within SQL Server Management Studio, 10,000 rows are inserted into the table.
When I run it from php it just aborts after about 150 rows (the number of rows varies, suggesting a timeout issue) with no error messages or any indication that it has finished early
The remote query timeout setting is set to the default of 600 seconds, so its not that.
The php:
$sql = "exec lalatest";
sqlsrv_query($cn, $sql);
I have tried specifying a timeout value (which should be indefinite by default anyway) on the sqlsrv_query line and it made no difference.
I'm using php 5.6.7
and Microsoft SQL Server 2012 (SP3) (KB3072779) - 11.0.6020.0 (X64)
Oct 20 2015 15:36:27
Standard Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor)
I have all errors and warnings turned on
Anyone got any ideas as to what I need to do to make this work?
Would you believe it, I have made it work. I added SET NOCOUNT ON as the first line in the stored procedure and now it works from php as well.
Looks like having the rows affected info throws the php sqlsrv driver a wobbly. Strange how it only does it after a certain time (about a second), perhaps something to do with when the message buffer is flushed or something. Yes, I'm guessing, but this has solved the problem, so I'm happy.
CREATE PROCEDURE lalatest
AS
BEGIN
SET NOCOUNT ON; -- must be added so that it will run from php
DECLARE #x int;
SET #x = 10000;
WHILE #x > 0
BEGIN
INSERT INTO lala (txt) VALUES ('blah ' + CAST(#x AS varchar(10)));
SET #x = #x - 1;
END;
END;
This might be a noob question, but I tried googling about this issue and I haven't found any solution for it (I think). Anyway, I need to compare a date in a row from a mysql table to the current date and update the row depending on the results. I made a stored procedure that will be called by an event every x minutes. Here is my code for the sp:
delimiter //
CREATE PROCEDURE checkPromoValidity()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE id INT;
DECLARE lvn_status INT;
DECLARE lvn_validUntil DATE;
DECLARE cur1 CURSOR FOR SELECT promos.PROMO_NUMBER,promos.VALID_UNTIL,promos.status FROM MDCH_NEW.promos;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
open cur1;
check_loop: LOOP
fetch cur1 into id,lvn_validUntil,lvn_status;
IF done THEN
LEAVE check_loop;
END IF;
IF (lvn_validUntil > CURDATE()) THEN
update mdch_new.promos set MDCH_NEW.PROMOS.status = 0 where mdch_new.promos.PROMO_NUMBER = id;
END IF;
end LOOP;
close cur1;
END //
MDCH_NEW = database name
PROMOS= table name
EDIT: I CHANGED my delimiter to // just to see
edit2: added space after the final word, still getting the error below.. :(
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 23
delimiter $$
create procedure return7 ()
BEGIN
select 7;
END
$$
call return7();
you are free to re-use this code
Trying to create my first stored procedure, I have researched extensively and could not find a way to input the code via phpMyAdmin so downloaded MYSQL Workbench 6.0 and put my script in that way- but it throws a 2014 error (Commands out of sync, you cannot run this command now). However I notice that Workbench seems to create two lines - the first says running and the second the error.
The routine is to update three tables and insert into another when a contract is issued. Contracts are made up of bundles and they in turn consist of items which relate to specific problems in another table.
Is it my code or should I include some clearing command at the end and if so what should that be? The procedure input is a contract id, user id and their IP address (for logging).
In PHP when, eventually, using a CALL how would I clear results, as I keep seeing Stackoverflow 2014 answers where second calls fail? Also how can I get this onto an ubuntu server either via phpMyAdmin or if with putty where should I ftp the sql script to?
DELIMITER //
DROP PROCEDURE IF EXISTS ContrctAwardStatusLog;
CREATE PROCEDURE ContrctAwardStatusLog( IN c_Id INT(8), IN u_Id INT(11), IN u_Ip varchar(20) )
BEGIN
Block1: BEGIN
DECLARE done INT DEFAULT 0;
DECLARE b_id INT DEFAULT 0;
DECLARE citm_id INT DEFAULT 0;
DECLARE r_id INT DEFAULT 0;
DECLARE c_1 CURSOR FOR SELECT bundle_id FROM bundles WHERE contract_id = c_Id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN c_1;
REPEAT
FETCH c_1 INTO b_id ;
Block2: BEGIN
DECLARE done2 INT DEFAULT 0;
DECLARE c_2 CURSOR FOR SELECT contitem_id, issue_id FROM c_items WHERE bundle_id= b_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2 = 1;
OPEN c_2;
REPEAT
FETCH c_2 INTO citm_id r_id;
INSERT INTO track_status (rowid, WStatusBy, WStatus, WStatusWhen) VALUES(r_id, u_Id, 13,NOW());
UPDATE h_issues SET WStatus='13' WHERE RowID = r_id;
UPDATE c_items SET act_state='13' WHERE contitem_id=citm_id;
UNTIL done2
END REPEAT;
CLOSE c_2;
END Block2;
UPDATE bundles SET bundle_stat = '13' WHERE bundle_id = b_id;
UNTIL done
END REPEAT;
CLOSE c_1;
END Block1;
END //
DELIMITER ;
I finally sorted this myself.
I needed to put the DROP ..if exists BEFORE the DELIMITER Setting and there was a syntax error in the FETCH after OPEN c_2. It was missing a comma separator.
DROP PROCEDURE IF EXISTS ContrctAwardStatusLog;
DELIMITER //
CREATE PROCEDURE ContrctAwardStatusLog( IN c_Id INT(8), IN u_Id INT(11), IN u_Ip varchar(20) )
BEGIN
Block1: BEGIN
DECLARE done INT DEFAULT 0;
DECLARE b_id INT DEFAULT 0;
DECLARE citm_id INT DEFAULT 0;
DECLARE r_id INT DEFAULT 0;
DECLARE c_1 CURSOR FOR SELECT bundle_id FROM bundles WHERE contract_id = c_Id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN c_1;
REPEAT
FETCH c_1 INTO b_id ;
Block2: BEGIN
DECLARE done2 INT DEFAULT 0;
DECLARE c_2 CURSOR FOR SELECT contitem_id, issue_id FROM c_items WHERE bundle_id= b_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2 = 1;
OPEN c_2;
REPEAT
FETCH c_2 INTO citm_id, r_id;
INSERT INTO track_status (rowid, WStatusBy, WStatus, WStatusWhen) VALUES(r_id, u_Id, 13,NOW());
UPDATE h_issues SET WStatus='13' WHERE RowID = r_id;
UPDATE c_items SET act_state='13' WHERE contitem_id=citm_id;
UNTIL done2
END REPEAT;
CLOSE c_2;
END Block2;
UPDATE bundles SET bundle_stat = '13' WHERE bundle_id = b_id;
UNTIL done
END REPEAT;
CLOSE c_1;
END Block1;
END //
DELIMITER ;
I'm new. Most of the times I find solutions here just by reading but now I have to ask you directly because of the weirdness of my subject.
I have an application in php and I used to use the mssql libraries to connect to MS Server 2008 but now I migrated part of my code to connect through ADODB http://adodb.sourceforge.net/
I have a store procedure which I use to validate/insert/update/delete rows depending of parameters I send, so at the very bottom I have a line of code like this
Select #Result Result
This variable just tell me everytime if the proccess went correctly or if I'm missing something so the row doesn't get inserted/deleted/updated.
Here the code of my store procedure
create procedure sp_MyTable #id int, #name varchar(100), #type varchar(10)
as
declare #Results varchar(100)
set #Result=#type
--validations!
if exists(select * from MyTable where name=#name)begin
set #Result='No insert:('
end
if #Result='insert'
insert into MyTable (name)values(#name)
select #Result Result
Here and example of code to create my connection in php
$pQry='exec sp_MyTable #id="0",#name="Hello",#type="insert"';
require ("php/ExtClases/adodb5/adodb.inc.php");
$db = ADONewConnection('mssqlnative');
$db->debug = false;
$db->Connect($datCon['sServer'], $datCon['UID'], $datCon['PWD'], $datCon['Database']);
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
$rs = $db->Execute($pQry);
$rows=$rs->GetRows();
So, it is supposed to return and Array like this
print_r($rows);
//Array ([0]=>Array( [Result] => insert )) )
But It prints just nothing.
Using Management Studio I already ran this procedure directly on my own computer and at the server online and both cases retrieved data, so the store procedure is fine.
If I remove the insert statement:
create procedure sp_MyTable #id int, #name varchar(100), #type varchar(10)
as
declare #Results varchar(100)
set #Result=#type
--validations!
if exists(select * from MyTable where name=#name)begin
set #Result='No insert:('
end
/*
No insert!
*/
select #Result Result
It works!.
print_r($rows);
//Array ([0]=>Array( [Result] => insert)) )
_UPDATE: even if I print something (print 'something') in the store procedure ADODB ignores the select statement, so the select must be totally alone.
I think I will consider searching for another way.
_.
PD: Sorry for my bad english.
Regards.
Well, it took a few hours of my appreciated life but at last now I know what is going on.
MSSQL driver use to ignore all but the last statement (as I remember...). So, if you have something like this
$query="select * from table1; select some, data from table2; select yadda yadda from table3";
$conn=mysql_connect($sServer,$UID,$PWD);
$baseDatos=mysql_select_db($Database,$conn);
$res=mysql_query($query);
While($row=mssql_fetch_array($res)){
print($row);
}
You will have printed the results only of table3.
( ACTUALLY Here it is written that you can have multiple recorset and navigate through them with mssql http://www.php.net/manual/es/function.mssql-next-result.php but at the moment I don't know why it takes just the last one as the first one. Maybe it doesn't recognize prints or inserts as recorsets at all)
ADODB library actually uses SQLSRV to handle connections and queries to any sql server (mssqlnative). SQLSRV is the official driver released for Microsoft so is slightly different. You need to use the function sqlsrv_next_result or it will be return just the first result whatever it is (print,insert,select,etc)
here the link
http://www.php.net/manual/en/function.sqlsrv-next-result.php
and another guy who had the same problem
SQLSRV and multiple selects in Stored Procedure
what I did is not pretty but with patience I think I can fix it in the future, for now I just need the last recorset (table3) and not the first, so ...
/*here my temporary fix*/
do {
$result = array();
while ($row = sqlsrv_fetch_array($this->_queryID)) {
$result[] = $row;
}
} while (!is_null(sqlsrv_next_result($this->_queryID)));
return $result;
/**/
I overwrite the variable $result with every step into the results :). Funny code.
Cheers
I need the list of all employees, following the hierarchy of the manager using MYSQL from the following table. In oracle or mssql it is easy job, but could not find any solution in MySQL. Can anyone help me out how to sort it out.
id name manager
1 John 6
2 Gill 7
3 Ben 2
4 Roy 8
5 Lenin 6
6 Nancy 7
7 Sam 0
8 Dolly 3
If you still can limit the maximal number of levels, here is a solution with a recursive procedure. Since recursive functions are not allowed in MySQL, we have here a function (manager_count), which wraps the results from the recursive procedure. Recursion depth is controlled by the max_sp_recursion_depth variable, which takes 255 as its maximum. Use as follows: SELECT *,manager_count(id) FROM my_table. It's not the optimal solution, since it doesn't take into account already counted branches of the hierarchy (a temporary table can actually serve as a cache).
DELIMITER //
DROP FUNCTION IF EXISTS manager_count//
CREATE FUNCTION manager_count(_manager INT) RETURNS INT
BEGIN
DECLARE _count INT DEFAULT 0;
SET max_sp_recursion_depth = 255;
# manager_count_helper does the job
CALL manager_count_helper(_manager, _count);
# subtract 1, because manager_count_helper will count this manager as well
RETURN _count - 1;
END//
DROP PROCEDURE IF EXISTS manager_count_helper//
CREATE PROCEDURE manager_count_helper(IN _manager INT, INOUT _count INT)
BEGIN
IF EXISTS (SELECT 1 FROM my_table WHERE id = _manager) THEN
BEGIN
DECLARE _next_manager INT DEFAULT 0;
DECLARE done BOOLEAN DEFAULT FALSE;
# cursor to loop through the employees
DECLARE _cursor CURSOR FOR SELECT id FROM my_table WHERE manager = _manager;
# if done, the done variable gets TRUE and it's time too leave
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
# count 1, because this guy should be counted as well
SET _count = _count + 1;
OPEN _cursor;
read_loop: LOOP
FETCH _cursor INTO _next_manager;
IF done THEN LEAVE read_loop;
END IF;
CALL manager_count_helper(_next_manager, _count);
END LOOP;
CLOSE _cursor;
END;
END IF;
END