PHP PDO Not Finding OUTPUT Parameter From MSSQL Stored Procedure Call - php

Been working at this for 3 days and tried every possible example instructions I could find in those 3 days. I have to ask for help in trying to understand what is not functioning here with regards to the OUTPUT parameter. This is a machine to machine operation, no terminal or webpage human interaction and only exists on an internal private subnet. Caller--> Cisco IVR-->PHP-->MSSQL DB-->PHP-->Cisco IVR--->Caller. I have included my entire PHP working script but I want to focus on why my parameter 3 statement does not function. My MSSQL stored procedure code 1st.
ALTER PROCEDURE [dbo].[pIOGetEligSSNDOB]
#SSN NVARCHAR(9),
#DOB NVARCHAR(8),
#RCODE INT OUTPUT
AS
BEGIN
SELECT * FROM ZASMasterDB.dbo.Eligibility WHERE SSN = #SSN AND DOB = #DOB
IF ##ROWCOUNT >= 1
SET #RCODE = 3
ELSE
SET #RCODE = 5
SELECT 'ReturnCode' = #RCODE
RETURN #RCODE
END
****My working PHP version 7.4.10 script using PDO****
$ID = $_GET['MEMBER_ID']; $DOB = $_GET['DOB'];
$start_time = microtime(true);
$sth = $pdo->prepare("exec dbo.pIOGetEligSSNDOB ?, ?, ? "); // I am using 2 INPUT and 1 OUTPUT
$RCODE = 0;
$row_count = 0;
$sth->bindParam(1, $ID); // Members social security number as INPUT to SQL server
$sth->bindParam(2, $DOB); // Members date of birth as INPUT to SQL server
$sth->bindParam(3, $RCODE, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT,10); //$RCODE to hold the OUTPUT integer
$sth->execute();
$time = round( (microtime(true) - $start_time), 4);
$col_count = 0;
//ARRAYS TO HELP ORGANIZE THE RESULTS
$column_name_array = array();
$rows_array = array();
// THE LOOP!
while($row = $sth->fetch(PDO::FETCH_ASSOC)){
$row_count++; // A MUST for the IVR to know how many records returned
$col_count = count($row);
$column_name_array = array_keys($row);
$row = array_map('trim',$row);
$rows_array[] = join("·", array_values($row)); //Delineation for the IVR
}
$sth = null;
$pdo = null;
?>
<response>
<time><?=$time?></time>
<cols><?=$col_count?></cols>
<rows><?=$row_count?></rows>
<code><?=$RCODE?></code> // This should be the value of the OUTPUT parameter from SQL DB
<column_names>
<?=join("·", $column_name_array)?>
</column_names>
<data>
<?=join("·", $rows_array)?>·
</data>
</response>
This is the result of the above code. It is perfect, except no OUPUT integer from SQL server to the $RCODE which would then display between the code elements.
This is the result of executing it in SQL Management Studio
I tried, changed the int value and still nothing. My PHP wont allow (? OUPUT) in the prepare line as the 3rd thing, doesn't like the ? mark. More research on here shows someone saying you need a DECLARE. So I made my line:
$sth = $pdo->prepare("DECLARE #RCODE INT; exec pIOGetEligSSNDOB ?,?, #RCODE OUTPUT; ");
and still no return value but PHP didn't complain, got my regular data back still. The I tried to use the exact same thing in my prepare line as I use manually when in SQL mgt studio.
$sth = $pdo->prepare("DECLARE #RCODE INT; exec pIOGetEligSSNDOB ?,?, #RCODE = #RCODE OUTPUT;");
and no $RCODE result.
So I had read about the whole "nextRowset" thing while I as pulling my hair out days ago, but then forgot about it while still trying to get something to work. Thank you for reminding me Zhorov!!. So I added the do to my original while and then added the while at the end of all the do, just like in those examples.
do {
while($row = $sth->fetch(PDO::FETCH_ASSOC)){
$row_count++;
$col_count = count($row);
$column_name_array = array_keys($row);
$row = array_map('trim',$row);
$rows_array[] = join("·", array_values($row));
}
} while ($sth->nextRowset());
And now my final XML output is a little differnet, and I do see the integer number 7 but it has been added at the end of my regular data fetch results rather than where I need it to go, and that is between the code elements. Then instead of all my regular column names that usually would display between the column name elements, it now shows the name 'ReturnCode', which I dont want to see. So I definitly have a formatting problem now. I did follow the examples of the nextRowset code exactly like they are explained, but somehow somethings wrong with the final output. This is very difficult when you are still trying to learn PHP and don't quite understand the placements and syntaxes of everything, but I am closer now than I was before.
So I believe I solved my own question here. It seems the 'Free TDS driver' I am using for my PHP PDO code does not support the use of OUTPUT parameters from MSSQL when first having the PHP execute the MSSQL stored procedure that returns the expected result set. The notes I found to support this was right here on Stack, but the link in those notes explaining why the OUTPUT parameter is not supported say that Microsoft did away with the OUTPUT parameter in MSSQL version 7 and up? Ver7 came out in 1998 I think. I don't know if that part is that true, but I can assure you, in my problem here, the OUTPUT parameter would not function at all. So the alternative was to use the nextRowset command in PHP, but NOT in the way that so many examples show. I had to figure it out myself, trial and error. I do not need a do..while loop and I do not need a while at the end of my original loop. Had to make the SQL code look like this.
CREATE PROCEDURE [dbo].[pIOGetEligSSDOB]
#SSN nvarchar(10),
#DOB nvarchar(10)
AS
BEGIN
DECLARE #RCODE int
SELECT * FROM ZASMasterDB.dbo.Eligibility WHERE SSN = #SSN AND DOB = #DOB
IF ##ROWCOUNT >= 1
SET #RCODE = 7
ELSE
SET #RCODE = 8
SELECT #RCODE
END
Then in PHP I keep my original working loop exactly the way it is and I added the 2 lines after the loop code. I first had to advance to the nextRowset like all of the example code showed, but I then have to go into that next rows column and pull out the single digit return code and put it into my $rcode to finally display on my XML output in the elements.
while($row = $sth->fetch(PDO::FETCH_ASSOC)){
$row_count++;
$col_count = count($row);
$column_name_array = array_keys($row);
$row = array_map('trim',$row);
$rows_array[] = join("·", array_values($row));
}
$sth ->nextRowset();
$rcode = $sth->fetchColumn();
So final output looks like:

we faced the same issue with a SP intended to return 3 out parameters cause of side effects on sql server thru a PDO call:
not sure this can help but you can try prefix your call to the SQL Server procedure with a "SET NOCOUNT ON;" statement before shooting
or begin and end yout Transact sql strored procedure by
SET NOCOUNT ON;
...
SET NOCOUNT OFF;
May work in your case ... or not if your SP calls extra procedure(s) where these flags are not correctly set...
We're still looking on a better solution...

Related

PHP PDO sqlsrv large result set inconsistency

I am using PDO to execute a query for which I am expecting ~500K results. This is my query:
SELECT Email FROM mytable WHERE flag = 1
When I run the query in Microsoft SQL Server management Studio I consistently get 544838 results. I wanted to write a small script in PHP that would fetch these results for me. My original implementation used fetchAll(), but this was exhausting the memory available to php, so I decided to fetch the results one at a time like so:
$q = <<<QUERY
SELECT Email FROM mytable WHERE flag = 1
QUERY;
$stmt = $conn->prepare($q);
$stmt->execute();
$c = 0;
while ($email = $stmt->fetch()[0]) {
echo $email." $c\n";
$c++;
}
but each time I run the query, I get a different number of results! Typical results are:
445664
445836
445979
The number of results seems to be short 100K +/- 200 ish. Any help would be greatly appreciated.
fetch() method fetches one row at a time from current result set. $stmt->fetch()[0] is the first column of the current row.
Your sql query has no ordering and can have some null or empty values (probably).
Since you are controlling this column value in while loop, if the current row's first value is null, it will exit from the loop.
Therefore, you should control only fetch(), not fetch()[0] or something like that.
Also, inside the while loop, use sqlsrv_get_field() to access the columns by index.
$c = 0;
while ($stmt->fetch()) { // You may want to control errors
$email = sqlsrv_get_field($stmt, 0); // get first column value
// $email can be false on errors
echo $email . " $c\n";
$c++;
}
sqlsrv_fetch

Why is this php code not fetching the first row from the mysql database?

It seems that this php code fetches all the rows in the database, but does not fetch the very first row. If you call to the procedure in the database (see the procedure below) it shows all the rows as expected. The database has four columns and in the code it's used echo to print out the data from the second row, What's happening is that the first record does not display, so it's not fetched I think. So, what could be the problem?
//this is the broken part of my code
$statement = $conn->prepare('call GetImage()');
$statement->execute();
while($row = $statement->fetch()){
$dest_slash = str_replace('-', '/', $row[2]);
$dest_slash_backslash = str_replace(';','\\', $dest_slash);
$replace_root = str_replace($_SERVER['DOCUMENT_ROOT'],'',$dest_slash_backslash);
$row[2] = $replace_root;
$images_paths_with_num[] = array($image_count,$row[2]);
$image_count++;
echo $row[1];
}
This is the stored procedure that I'am using:
CREATE DEFINER=`0901972749`#`%` PROCEDURE `GetImage`()
begin
select imageID,imageName,imagePath,imageText
from Images limit 500;
end
See this procedure (The same as in the question):
CREATE DEFINER=`0901972749`#`%` PROCEDURE `GetImage`()
begin
select imageID,imageName,imagePath,imageText
from Images limit 500;
end
It was needed to add an order by statement in this case "order by imageID" to it as things were not displaying in the right order. To be sure about the data will display in the right order, we need to use an order by clause. But, stored procedures may not be the right solution for this. Sorry about that :)
Like this:
CREATE DEFINER=`0901972749`#`%` PROCEDURE `GetImage`()
begin
select imageID,imageName,imagePath,imageText
from Images limit 500 order by imageID;
end

Blank result for some columns when php mysql_query, works in phpmyadmin

I've run into a problem that is making me go a bit crazy. I have imported some csv data into a table in my phpadmin database and am now using a php script with mysql_query() to run a simple select query on the database and convert the result into json format - e.g. SELECT clients FROM TABLE 29.
Basically, some of the columns in the table result in a json string after passing them through mysql_query() but others simply return a blank. I have fiddled for hours now and can't figure out why this is. The last bit of my code looks like this:
$myquery = "SELECT `clients` FROM `TABLE 29`";
$query = mysql_query($myquery) or die(mysql_error());
if ( ! $query ) {
echo mysql_error();
die;
}
$data = array();
for ($x = 0; $x < mysql_num_rows($query); $x++) {
$data[] = mysql_fetch_assoc($query);
}
echo json_encode($data);
mysql_close($server);
Any help would be greatly appreciated. Could it be something about the data in the table? I'm at a loss.
thank you!
UPDATE: the length of the strings in the column clients seems to be having an effect. When I replace all the text with something shorter (e.g. aaa instead of something like company name 111 - 045 - project name - currency - etc) it works. However, I need it to be able to handle long strings as I want it to just take whatever users happen to import into it... what am I doing wrong?
No, its not about the table, its about how you loop them. Example:
$data = array();
while($row = mysql_fetch_assoc($query)) { // While a row of data exists, put that row in $row as an associative array
$data[] = $row;
}
echo json_encode($data);
mysql_close($server);
exit;
Note: mysql is depreacted and no longer maintained. Use the improved version of the mysql extension which is mysqli or use PDO instead.
After checking all the rows of the data I discovered that the source of the problem was a 'é' - yes, an 'e' with an accent. Once I replaced it with a regular 'e' the problem went away. So much lost time for something so tiny :(

Get detailed field information for a pgsql resultset in php

I have been trying to get the complete meta information for the fields in a result set from Postgresql in php (something like mysql_fetch_field(), which gives a lots of info about the field definition). While I am able to use the following functions to find some information:
$name = pg_field_name($result, 1);
$table = pg_field_table($result, 1);
$type = pg_field_type($result, 1);
I could not find a way to get more details about whether the field allow null values, contains blob data (by field definition), is a primary,unique key by definition etc. The mysql_fetch_field() gives all of this information somehow, which is very useful.
I would really like some way to get that information from php directly, but if that is not possible, then maybe someone has created a routine that might be able to extract that info from a pgsql resultset somehow.
PS: This looks promising, but the warning on the page is not a good sign:
http://php.net/manual/en/pdostatement.getcolumnmeta.php
Also, I am not using PDO at the moment, but if there is no solution, then a PDo specific answer will suffice too.
You can find the metadata on you column with a query like this:
select * from information_schema.columns
where table_name = 'regions' and column_name = 'capital'
This should provide all of the information found in mysql_fetch_field. I'm not a php coder, so perhaps someone knows of a function that wraps this query.
All;
Was amazed to find pgsql does not have a column count routine in PHP. The helps I looked up all got total count from "information_schema.columns", which is not what you want when doing cell by cell processing.
So here is a couple of quick functions to use:
// Test Cell by Cell
echo "Testing Cell by Cell! <br>";
$sql = "SELECT * FROM sometable;
$res = pg_query($sql);
$r_cnt = pg_numrows($res) or die("Error: Row Count Failed!");
$c_cnt = pg_numcols($res) or die("Error: Col Count Failed!");
echo "C=> $c_cnt R=> $r_cnt <br>";
for ($n=1; $n<=$r_cnt; $n++) {
for ($x=1; $x<=$c_cnt; $x++) {
echo "Cell=> pg_result($res,$n,$x) <br>";
} // end while $x
} // end while $n
function pg_numcols($res) {
$spos = strpos(strtoupper($this->db_sql),'SELECT')+6;
$fpos = strpos(strtoupper($this->db_sql),'FROM');
$lenp = $fpos - $spos;
$t_str = substr($this->db_sql,$spos,$lenp);
$x_str = explode(',',trim($t_str));
$result = count($x_str);
return $result;
} // end function
Hope you enjoy!

How to loop through returned SQL results - nextRecord()

I have a stored procedure that returns multiple result sets from an MSSQL database. The problem I'm having is looping through each result set. It seems Yii is not advancing to the next result set to iterate through the rows. Here is an example:
RESULT 1:
TOTAL
-----
999
RESULT 2:
ID |NAME
---|----
0 | Jon
1 | Bob
2 | Sarah
3 | Pete
And here's my attempt at making this work in Yii.
//create the call to stored proc
$command=parent::$db->createCommand("exec sp_showUsers");
//run the query
$dataReader = $command->query();
//For the current object assign the row to a variable
while (($row = $dataReader->read()) !== false){
//if the row has a total column
if(isset($row['total'])){
$total = $row['total'];
}
}
//Test if there is another result
$usersExist = $dataReader->nextResult();
//$dataReader->next(); - REMOVED AS NOT NEEDED
if($usersExist){
$userTable = array();
$i = 0;
while (($userRow = $dataReader->read())!== false){
//add each row to a temporary array
$userTable[$i] = $userRow['id'];
$i++;
}
}
...
This doesn't seem to loop through the second result set even though the ->next() method has been called? Any help would be very appreciated! Thanks.
P.s The stored procedure does work and I can loop through the results using ordinary PHP and the sqlsrv_next_result() method.
In the code, why
$dataReader->nextResult() will return a CDbDataReader Object.
So, you are using $dataReader->next(); this will move the pointer of first result only. You have to move the pointer returned by nextResult() call.
I think,
$dataReader=$dataReader->next();
will solve the problem
I found the answer. It was the way we were binding the params to our stored procedure that was messing up our results. We don't need the $dataReader->next(); at all. so all is working ok with the code above. I hope this helps someone out who is using SQL server stored procedures with Yii. :) And just in case anyone needs the stored procedure call example:
$command=parent::$db->createCommand("exec sp_showUsers :pageNumber, :pageSize, :sortOrder, :viewAll");
$command->bindParam(":pageSize", $pageSize, PDO::PARAM_INT);
$command->bindParam(":pageNumber", $pageNumber, PDO::PARAM_INT);
$command->bindParam(":sortOrder", $sortOrder, PDO::PARAM_STR);
$command->bindParam(":viewAll", $viewAll, PDO::PARAM_BOOL);
$dataReader = $command->query();

Categories