Why this php code does not execute the SqL Server query completely? - php

I am having trouble with this php code, the problem is that I have tried to insert 1000 rows on a Sql Server table but the code just inserts 80 rows and I do not know why, I have executed the Sql Server procedure alone on the Sql Server Management Studio and works good but when I try to execute from php It does not work, I also set the "remote query time out" to "no timeout". Here is the code that I am using. Help please.
PHP CODE
<?php
$myServer = "servername";
$conex=array("Database"=>"database");
$conn = sqlsrv_connect ($myServer, $conex) ;
if ( sqlsrv_begin_transaction( $conn ) === false ) {
die( print_r( sqlsrv_errors(), true ));
}
$sql="insertarDistrito_Sql ?";
$params=array(&$_POST(1000));
$stmt=sqlsrv_query($conn, $sql, $params);
if( $stmt) {
sqlsrv_commit( $conn );
echo "Transaction committed.<br />";
} else {
sqlsrv_rollback( $conn );
echo "Transaction rolled back.<br />";
}
?>
SQL SERVER STORED PROCEDURE
CREATE procedure [dbo].[insertarDistrito_Sql]
#cant int
As
Declare #i int
Declare #w int
Declare #id int
SET #i = 1
set #w=1
set #id=1
if (Select count(*) from distrito)> 0
begin
Set #id= (select max([id_distrito]) from [dbo].[distrito])
set #id=#id+1
end
WHILE(#i <= #cant)
BEGIN
INSERT INTO [dbo].[distrito] ([id_distrito], [id_warehouse], [d_nombre], [d_direccion], [d_calle1],
[d_calle2],[d_barrio], [d_fecha_creacion],[d_capacidad])
VALUES(#id,#w,newid(),newid(),newid(),newid(),newid(), '12/12/2014',rand())
SET #i += 1
set #id +=1
END

It could be PHP that is timing out, try putting
set_time_limit(0);
at the top of your PHP file.

Related

PHP sqlsrv_fetch_array problem && sqlsrv_num_rows -1

a new webserver has been stood up for me. It is Ubuntu 20.04 and has PHP 7.4.3 on it. I am working with MS SQL Server 2012. I can send my SQL query to the DB server and see it in SQL Server Profiler. I can copy it from the profiler and it runs fine in SQL Management Studio but, I am having a problem when I try to echo the results to my page. When I use sqlsrv_num_rows I get -1. Could I get a hand please?
<?php
if(isset($_POST['getPassBtn'])){
#DATABASE LOGIN
include './php/inc/dbLogin/mydb.php';
#FORM POST VARIABLES
$badge = $_POST['empId'];
//$badge = (int)$badge;
#check badge entry for paramiters
if($badge == '' || $badge < 10000 || $badge > 30000){
echo '<br/> ERROR : Invalid Badge Number <br/>';
die();
}
$sql = "USE mydb SET NOCOUNT ON SELECT badgeNumber, userPassword FROM dbo.users WHERE badgeNumber = '$badge' ORDER BY badgeNumber ASC --getTestData.php";
//$sql = "USE toolsMeskwaki SELECT * FROM bingoProgressive.users ORDER BY badgeNumber ASC --getTestData.php";
$params = array();
$options = array( 'Scrollable' => 'buffered');
$stmt = sqlsrv_query( $conn, $sql, $params, $options);
#check if query returns false
if( $stmt === false ) {
die( print_r( sqlsrv_errors(), true));
}else{
echo '<br/> Query sent to SQL Server <br/>';
}
/*
$row_count = sqlsrv_num_rows( $stmt );
if ($row_count === false){
echo "Error in retrieveing row count.";
}else{
echo $row_count;
}
*/
#Fetching Data by array
while($row = sqlsrv_fetch_array($stmt)){
echo 'badgeNumber '.$row['badgeNumber'];
echo 'userPassword '.$row['userPassword'];
}
#release query
sqlsrv_free_stmt($stmt);
#CLOSE DATA BASE CONNECTION
sqlsrv_close($conn);
echo "<br/> SQL Server Connection closed.<br />";
}else{
echo '<br/> click GET btn to connect SQL Server <br/>';
}
?>
You're submitting three different statements:
USE mydb
SET NOCOUNT ON
SELECT badgeNumber, userPassword FROM dbo.users WHERE badgeNumber = '$badge' ORDER BY badgeNumber ASC
It works in SQL Management Studio for two reasons:
Auto-magic statement detection, although deprecated for several years (you're now expected to use ; as delimiter), is still supported.
The query tool is specifically designed to run several statements at once.
We know that sqlsrv_query() supports it because it isn't returning false. But, given that you're running three statements, you need you use sqlsrv_next_result() twice to move to the third result set.
On a side note:
You can use sqlsrv_connect() to provide the initial database. You only need to switch DBs if you use several of them and you don't want to add the name as mydb.dbo.users.
SQLSRV supports prepared statements (see sqlsrv_prepare() and sqlsrv_execute()).

Does sqlsrv_query limit the number of statements that can be exectuted in one query?

I am generating a SQL insert statement within a PHP for loop.
The SQL string generated is a large number of individual SQL statements like this:
INSERT INTO tbl VALUES(1,2,3);
INSERT INTO tbl VALUES(4,5,6);
INSERT INTO tbl VALUES(7,8,9);
etc...
Then I execute with:
$InsertResult = sqlsrv_query($conn, $InsertSQL);
The problem is that only the first 312 statements get executed instead of the full 2082 lines (only 312 rows are inserted into the table).
When I output the $InsertSQL variable to the JavaScript console and then execute it manually in SSMS it works perfectly and inserts all 2082 lines. Only when I run the $InsertSQL variable through sqlsrv_query does it not go to completion.
I also don't get any errors and the query result comes back true as tested in this line:
if(!$InsertResult) die('Problem with Insert query: ' . $InsertSQL);
When I searched for a solution to this problem I saw that (although it's not mentioned in the PHP manual site) sqlsrv_query apparently has a string character limit on the $SQL variable (around 65k characters).
See the other StackOverflow article here:
length restriction for the sql variable on sqlsrv_query?
I figured this was the problem and so created a shorter version of the string (by only adding in the column values that I actually wanted to import). This much shorter version however, still only Inserts the first 312 lines! So now it seems this is NOT related to the max string length. In fact, if it was, I should only get around 250 lines (after 250 statements I'm at about 65k characters).
I can also execute each insert statement individually but of course this takes much longer. In my testing, it takes 90s or so to do it this way where as running the combined statement manually in SMSS takes only around 40s.
Note that I've also looked into SQL Server's Bulk Insert however I won't be able to send the file to the machine where SQL Server is installed (SQL Server and Web servers are on separate computers). From my understanding this eliminates this possibility.
Any help is much appreciated as I can't even figure out what it is that is limiting me, never mind fix it and I'd hate to have to execute one line at a time.
Explanations:
There is a known issue with this driver, posted on GitHub, about executing large SQL statements. One part of the provided solution are the following explanations:
Seems like when executing a large batch of SQL statements, Microsoft SQL Server may stop processing the batch before all statements in the batch are executed. When processing the results of a batch, SQL Server fills the output buffer of the connection with the result sets that are created by the batch. These result sets must be processed by the client application. If you are executing a large batch with multiple result sets, SQL Server fills that output buffer until it hits an internal limit and cannot continue to process more result sets. At that point, control returns to the client. This behavior is by design.
Client app should flush all the pending result sets. As soon as all pending result sets are consumed by the client, SQL Server completes executing the batch. Client app can call sqlsrv_next_result() until it returns NULL.
So, I don't think that there is a limit for the SQL statement length, only the size of a PHP string variable ($InsertSQL in your case) is limited to the maximum allowed PHP memory limit. The actual reason for this unexpected behaviour is the fact, that with SET NOCOUNT OFF (this is by default) and a large number of single INSERT statements, the SQL Server returns the count of the affected rows as a result set (e.g. (1 row affected)).
Solution:
I'm able to reprodiuce this issue (using SQL Server 2012, PHP 7.1.12 and PHP Driver for SQL Server 4.3.0+9904) and you have the following options to solve this problem:
Flush the pending result sets using sqlsrv_next_result().
Execute SET NOCOUNT ON as first line in your complex T-SQL statement to stop SQL Server to return the count of the affected rows as a resultset.
Use parameterized statement using sqlsrv_prepare()\sqlsrv_execute()
Table:
CREATE TABLE MyTable (
Column1 int,
Column2 int,
Column3 int
)
One complex statement (using sqlsrv_query() and sqlsrv_next_result()):
<?php
// Connection info
$server = 'server\instance';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
// Statement with sqlsrv_query
$sql = "";
for ($i = 1; $i <= 1000; $i++) {
$sql .= "INSERT INTO MyTable (Column1, Column2, Column3) VALUES (".$i.", 0, 0);";
}
$stmt = sqlsrv_query($con, $sql);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
// Clean the buffer
while (sqlsrv_next_result($stmt) != null){};
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
echo "OK";
?>
One complex statement (using sqlsrv_query() and SET NOCOUNT ON):
<?php
// Connection info
$server = 'server\instance';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
// Connection
$con = sqlsrv_connect($server, $cinfo);
if ($con === false) {
echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
exit;
}
// Statement with sqlsrv_query
$sql = "SET NOCOUNT ON;";
for ($i = 1; $i <= 1000; $i++) {
$sql .= "INSERT INTO MyTable (Column1, Column2, Column3) VALUES (".$i.", 0, 0);";
}
$stmt = sqlsrv_query($con, $sql);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
echo "OK";
?>
Parameterized statement (using sqlsrv_prepare() and sqlsrv_execute()):
<?php
// Connection info
$server = 'server\instance';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
// Connection
$con = sqlsrv_connect($server, $cinfo);
if ($con === false) {
echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
exit;
}
$sql = "INSERT INTO MyTable (Column1, Column2, Column3) VALUES (?, ?, ?);";
$value1 = 0;
$value2 = 0;
$value3 = 0;
$params = array(&$value1, &$value2, &$value3);
$stmt = sqlsrv_prepare($con, $sql, $params);
if ($stmt === false ) {
echo "Error (sqlsrv_prepare): ".print_r(sqlsrv_errors(), true);
exit;
}
for ($i = 1; $i <= 1000; $i++) {
$value1 = $i;
$value2 = 0;
$value3 = 0;
$result = sqlsrv_execute($stmt);
if ($result === false) {
echo "Error (sqlsrv_execute): ".print_r(sqlsrv_errors(), true);
exit;
}
}
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
echo "OK";
?>

Complex stored procedure not executing when called by sqlsrv_execute

I've written a rather complex stored procedure in SQL Server 2012 that I know selects "1" multiple times when executed. When I run it in SQL Management Studio, it executes and the rows of my table update correctly. However, when I use the code below to call it from PHP, it's not executing:
$Month = 2;
$Year = 2016;
$connectionInfo = array("Database"=>"Finances", "UID"=>"sa", "PWD"=>"abcd1234");
$connection = sqlsrv_connect("localhost", $connectionInfo);
if( $connection === false ) {
die( print_r( sqlsrv_errors(), true));
}
$stmt = sqlsrv_prepare($connection, "exec UpdateBudgetToMatchTransactions #Month=?, #Year=?", array(&$Month, &$Year));
if (sqlsrv_execute($stmt) === false) {
die( print_r( sqlsrv_errors(), true));
}
SQL Profiler says the following is happening on the server:
declare #p1 int
set #p1=NULL
exec sp_prepexec #p1 output,N'#P1 int,#P2 int',N'exec UpdateBudgetToMatchTransactions #Month=#P1, #Year=#P2',2,2016
select #p1
go
However, the rows are not affected in the way they are when I call the stored procedure directly. Further, if I take that block of SQL and execute it in it's entirety in SQL Management Studio, the rows change how I'd expect them to.
I appreciate any assistance in determining what I'm doing wrong.
My master stored procedure did not include one line that was already in the sub procedures. I have added this line in the master stored procedure as well and now this behaves very well.
Have a look at adding "SET NOCOUNT ON" in the beginning of the procedure and give it a try !!

PHP Get return value from MSSQL Stored Procedure

I can't get the OUTPUT parameter from my SQL Server (MSSQL 2012) SP to return to PHP. My Stored procedure is:
CREATE PROCEDURE spGetNextSeqID #ID AS INT OUTPUT
AS
BEGIN
BEGIN TRANSACTION
SELECT #ID = SEQUENCE_NO + 1 FROM tblCSRSequence WITH (TABLOCKX)
UPDATE tblCSRSequence SET SEQUENCE_NO=#ID
COMMIT TRANSACTION
END
And my PHP code is:-
<?php
include "DBConnect.php";
$conn = sqlsrv_connect( $serverName, $connection);
if( !$conn )
{
echo "Connection could not be established to ".$serverName;
die( print_r( sqlsrv_errors(), true));
}
$sql="{call dbo.spGetNextSeqID( ? )}";
$outSeq=0;
$params = array
(
array($outSeq, SQLSRV_PARAM_OUT)
);
$stmt = sqlsrv_query( $conn, $sql, $params );
if( $stmt == false)
die( print_r( sqlsrv_errors(), true) );
sqlsrv_free_stmt( $stmt);
sqlsrv_close( $conn );
echo $outseq;
?>
I know the SP is getting called and working - I checked it with a trace and can see that it's generating the following:-
declare #p1 varchar(max)
set #p1='154'
exec dbo.spGetNextSeqID #p1 output
select #p1
Each time I refresh my browser page it calls the SP and increments the counter by 1 but never returns the value to the calling PHP function. I've been fiddling with this for about 2 days now - I've scoured the similar posts but none of the suggested fixes (like SET NOCOUNT ON etc) work.
Anyone got any ideas?
New:
I missed that you are using a single parameter as both input and output. Please try the following.
array($outSeq, SQLSRV_PARAM_INOUT)
Then using
sqlsrv_next_result($stmt);
echo $outSeq;
Reference:
http://technet.microsoft.com/en-us/library/cc644932(v=sql.105).aspx
Old:
You must set up $outSeq with the appropriate data type. Try initialize the value to $outSeq = 0.00, since your output type is MONEY.
Please reference the following article:
http://technet.microsoft.com/en-us/library/cc626303(v=sql.105).aspx

Getting output of MS stored procedure on php call

I am using the sqlsrv ms drivers for php, which work fine (tested with normal queries). I have also tested it with running a stored procedure to update a table data, which also works.
Now I want to use it to run a stored procedure, and I want to retrieve the response. How can this be done?
$server = "...the server address...";
$options = array("UID"=>"...the username...","PWD"=>"...the password...",
"Database" => "...the database..."
);
$conn = sqlsrv_connect($server, $options);
if ($conn === false) {die("<pre>".print_r(sqlsrv_errors(), true));}
$tsql_callSP = "{call ...the stored proc...( ?, ?)}";
$params = array(
array("...first value in...", SQLSRV_PARAM_IN),
array("...second value in...", SQLSRV_PARAM_IN)
);
$stmt3 = sqlsrv_query( $conn, $tsql_callSP, $params);
if( $stmt3 === false )
{
echo "Error in executing statement 3.\n";
die( print_r( sqlsrv_errors(), true));
}
print_r( $stmt3); //attempting to print the return but all i get is Resource id #3
echo "test echo";
sqlsrv_free_stmt( $stmt3);
sqlsrv_close( $conn);
I know that I can use an output parameter, but I will always receive multiple values from the stored proc.
Supposing that the stored procedure is returning the contents of one table with a single SELECT statement, using its output should be as simple as using the result of sqlsrv_query as you would any other selection query result (i.e. using sqlsrv_fetch_object/array on the result)!
So the stored proc could look something like this:
CREATE STORED PROCEDURE test
AS
-- do some other stuff here
-- ...
SELECT * FROM test
GO
And in your php:
// establish db connection, initialize
// ...
$sql = "{call test}"
$result = sqlsrv_query($conn, $sql);
while (sqlsrv_fetch_object($result))
{
// do something with the data
// ...
}
You need to call sqlsrv_fetch() and sqlsrv_get_field() to get data from the returned statement.
From the example code in the manual for sqlsrv_get_field:
$stmt = sqlsrv_query( $conn, $tsql);
if( $stmt === false )
{
echo "Error in statement preparation/execution.\n";
die( print_r( sqlsrv_errors(), true));
}
/* Make the first row of the result set available for reading. */
if( sqlsrv_fetch( $stmt ) === false )
{
echo "Error in retrieving row.\n";
die( print_r( sqlsrv_errors(), true));
}
/* Note: Fields must be accessed in order.
Get the first field of the row. Note that no return type is
specified. Data will be returned as a string, the default for
a field of type nvarchar.*/
$name = sqlsrv_get_field( $stmt, 0);
echo "$name: ";
Beyond that, I am not sure when you say you will receive multiple values whether you mean there will be multiple fields in one row (in which case you will want to make more calls to sqlsrv_get_field()), more than one row (in which case you will have to use a while loop with the call to sqlsrv_fetch() in the loop), or more than one result set (in which case you'll want a while loop using sqlsrv_next_result()).

Categories