I have a stored proc that does a geospatial query. The proc issues two sql statements but only the 2nd one does a query but unfortunately both statements produce a result set. I need the second result set which contains the results of the actual query.
The first statement sets a bounding box:
SET #bbox = 'POLYGON(($polygon))'; \n
SELECT * , AsText( location )
FROM users
WHERE Intersects( location, GeomFromText( #bbox ) ) [snipped for brevity]
If I run the above in phpMyAdmin, it works but I get the following message AFTER the SET command is issued and I want to throw this away:
# MySQL returned an empty result set (i.e. zero rows).
On the php side, I build the query string, calling the stored proc and on return the first thing I do is throw away the empty result set.
$query = "CALL usp_queryByPolygon('$polygon', $msg_id, $user_type)";
$result = mysqli_query($cxn, $query) or die("GEOCODE: queryPolygon - " .sql_error());
sql_free_result($result);
After throwing away the result set I now need the results of the query and this is what I have done:
$result = sql_next_result();
The problem is when I try to use this second result set as in:
if(mysqli_num_rows($result) > 0)
I get errors:
Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given
in /blah/blah/module.php on line 96
To complicate things, all of the above is in a loop and there could be dozens or 100's of polygons to search.
So the question is this: what is the proper way to get that 2nd result set?
You'd better be accurate of what functions you execute. sql_next_result() is no standard PHP function, nor is it in MySQLi which you seem to use. If it's some kind of database class, please just show the methods that class uses. Nobody here can but quess what sql_next_result() does.
Assuming you're talking about mysqli_next_result(), that indeed returns a boolean, you need to call mysqli_use_result() after that in order to retreive the next result set.
Found out the two statements: SET #bbox and SELECT can be executed sequentially so mysqli and the two results are just fodder that don't need to be dealt with.
Related
I have a conundrum that appears to defy logic, involving Lumen, PHP, PDO, and SQL Server.
I have a controller which contains an action, that executes a stored procedure on a QL Server instance before returning the results as a JSON string. Nothing special is happening but for certain parameters, I do not get any response.
Right, some code. Here's the PHP/PDO prepared statement.
// Prepare our query.
$query = $pdo->prepare("
EXEC [dbase].[dbo].[myStoredProc]
#A = :A,
#B = :B,
#C = :C,
#D = :D,
#E = :E,
#F = :F,
#G = :G
");
// Bind the parameters and execute the query.
$query->bindParam(':A', $A);
$query->bindParam(':B', $B);
$query->bindParam(':C', $C);
$query->bindParam(':D', $D);
$query->bindParam(':E', $E);
$query->bindParam(':F', $F);
$query->bindParam(':G', $G);
$query->execute();
// Uncomment the following line for debugging purposes.
$query->debugDumpParams();
// Lets get all of the data.
$data = $query->fetchAll(\PDO::FETCH_ASSOC);
print_r($data);
Perfectly normal as I said. If I use POSTMAN and pass in the parameters as follows:
A 'C_ICPMS_06'
B 'AQC1'
C '726'
D NULL
E '2021-08-30 00:00:00'
F '2021-11-30 23:59:59'
G NULL
I get a list of results as expected, both from POSTMAN and PHP as well as through SSMS (using the output from the debug statement).
Now if I change parameter C from '726' to '728', I do not get any output from POSTMAN and PHP, but still, get output from SSMS.
Thinking that there could be some text within the output that is breaking the FETCHALL function, I amended the stored procedure to return a single record, all columns containing 1's. Once more the parameter of 726 works, 728 does not.
I added a VAR_DUMP command to ensure that the parameter isn't being molested on its way to the controller, both parameter values report that they are strings with 3 characters in length.
if I change the prepared statement as below, I still don't get any results seen within POSTMAN/PHP.
// Bind the parameters and execute the query.
$query->bindParam(':A', $A);
$query->bindParam(':B', $B);
//$query->bindParam(':C', $C);
$query->bindValue(':C', '728');
$query->bindParam(':D', $D);
$query->bindParam(':E', $E);
$query->bindParam(':F', $F);
$query->bindParam(':G', $G);
$query->execute();
The debug SQL statement is identical to before (using the param as opposed to value).
If I change the stored procedure, such that regardless of what value is passed in for parameter C, it is hardcoded to 728, it works as intended (obviously it does not matter what the parameter is set within POSTMAN). So I get values within POSTMAN and SSMS, therefore, it is safe to assume that the whole problem is being caused by the parameter and value '728'.
Further digging at this issue, I find that if the parameter has a value of '72F' or '70W', also returns no results via POSTMAN/PHP but does from within SSMS. I've checked and cannot see any error messages being produced.
I added the below lines to the controller to see if I can see an issue, but nothing was seen (not on screen nor within error files).
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
In trying to figure this out, I created a temporary database table in order to capture the input parameters and the number of records as found within the SP. This should show where the problem lies, i.e. within PHP or within SQL Server. It now gets stranger.
Calling the SP from within SSMS, it populates with an expected record, including the number of records the initial search returned. However, calling it from POSTMAN using the controller, everything is the same in terms of parameters, but the number of records found is 0!
So I know something very weird is going on, but cannot put my finger on what and therefore how to fix it. If anyone has any ideas or has come across a similar problem, please let me know. this is bugging me now. No doubt when I get this working, it'll be a silly error and I'll end up kicking myself.
The issue was that a temporary table that was being created couldn't hold a specific value being assigned to it. The column was designated as a TINYINT but should have been a SMALLINT since the value could go negative.
Why SSMS never reported that as an issue and happily allowed it through, God only knows. But when called externally, it failed to insert any records within the temporary table, returning no records as a result.
There go 1.5 days of my life never to be seen again.
I can't seem to figure out what's wrong with this PHP code:
$sql = $db->prepare("SELECT EXISTS(SELECT 1 FROM profile WHERE uid = ?)");
$p_already_exists = $sql->execute([$_SESSION['uid']]);
I'm running the sqlite3 PDO module, and it doesn't matter whether the 'uid' is in the database or not, $p_already_exists is always assigned 1. I'm expecting for it to be 0 if it's not in the database, and 1 if there is at least one record in the database.
I've double checked that echoing out $_SESSION['uid'] gives me the same value to uid (TEXT) in the database.
Does anybody know why this isn't working for me? At the end of the day I'm just after an efficient way of returning a boolean value (hence why I'm not using COUNT). Appreciate your help.
ref How to check whether SELECT EXISTS returns a value or not?
PDOStatement::execute() returns a boolean value, TRUE on success or FALSE on failure:
https://www.php.net/manual/en/pdostatement.execute.php
If you want to get the actual result returned by the SQL statement execution, rather than the status of the execution itself, you should use one of the fetch* functions, for example fetchColumn(), after calling execute().
I can not get an SQL update statement to subtract a variable from a table value. Here is my code:
$_SESSION_Job101=mysql_fetch_array(mysql_query("SELECT * FROM job_101 WHERE job_101.username='$_SESSION_User'"));
mysql_query("UPDATE characters SET currenergy=currenergy-$_SESSION_Job101['ecost'] WHERE username='$_SESSION_User'");
$_SESSION_Job101 is a perfectly valid result, as I pull from it on another page; I even pull the 'ecost' on said page. I also update currenergy this way in another script, except I use the number 1 instead of the variable. So I've narrowed it down to that variable.
It wouldn't matter that $_SESSION_Job101 is the result from a second table (job_101), and that query is updating to the table characters, would it?
We don't have enough information, but since you don't perform ANY error handling or validation that SQL resultset is returned, it could be an error caused by issues such as:
no rows returned in first query
some other parsing issue not directly evident
I would propose that you use temporary strings and echo the actual SQL queries.
Continue by actually testing them with MYSQL (through workbench, queryviewer, or console) in order to see where and what the error is.
Also, it's not recommended to skip error checking and try to combine so many lines/steps into 2 lines.
Imagine the first query does not return any results for example...
Debugging:
$query1 = "SELECT * FROM job_101 WHERE job_101.username='$_SESSION_User'";
echo $query1."<br/>";
$_SESSION_Job101=mysql_fetch_array(mysql_query($query1 ));
$query2 = "UPDATE characters SET currenergy=currenergy-$_SESSION_Job101['ecost'] WHERE username='$_SESSION_User'";
echo $query2."<br/>";
mysql_query($query2);
Update
Based on your comment I suggest you try the following two options:
1) Add a space between the - and $_SESSION_Job101['ecost'].
2) If that doesn't work, change your string to:
mysql_query("UPDATE characters SET currenergy=currenergy-".$_SESSION_Job101['ecost']." WHERE username='".$_SESSION_User."'";`
In the MySQL Reference Manual, there's distinction between data definition statements and data manipulation statements.
Now I want to know if a query inserts a database record, updates one, deletes one or modifies the table structure and so on, or, more precisely, the exact number of affected rows, but only if it is applicable.
For example, the statement
SELECT *
FROM SomeTable
WHERE id=1 OR id=2
returns a number of affected rows (in this case 2), but with the SELECT statement, there's nothing modified in the database, so that number would be 0.
How to get the type of query?
I was looking for the same answer and stumbled across this article. It was last updated in August. In it, there is a section: "Determining the Type of a Statement" You basically can make the following assumptions: (copied from the article)
If columnCount() is zero, the statement did not produce a result set. Instead, it modified rows and you can invoke rowCount() to determine the number of affected rows.
If columnCount() is greater than zero, the statement produced a result set and you can fetch the rows. To determine how many rows there are, count them as you fetch them.
I'll save you the trouble and just paste the code sample here
$sth = $dbh->prepare ($stmt);
$sth->execute ();
if ($sth->columnCount () == 0)
{
# there is no result set, so the statement modifies rows
printf ("Number of rows affected: %d\n", $sth->rowCount ());
}
else
{
# there is a result set
printf ("Number of columns in result set: %d\n", $sth->columnCount ());
$count = 0;
while ($row = $sth->fetch (PDO::FETCH_NUM))
{
# display column values separated by commas
print (join (", ", $row) . "\n");
$count++;
}
}
I have been thinking of the same issue, and come to conclusion that I don't need no automation in this matter.
The only use for such an auto-detect is some magic function which will return number of affected rows. But such a magic, although adding a little sugar to the syntax, always makes code support a nightmare:
When you're calling a function, and it can return values of different types depends on the context, you cannot tell which one is returned at every particular moment. So, it makes debugging harder.
So, for sake of readability, just call appropriate function to get the result you need at the moment - affectedRows or numRows. It won't make your code bloated, but make it a lot readable.
I'm using this:
substr($statement->queryString, 0, strpos($statement->queryString, ' '));
where $statement is a PDOStatement object, a few things to note here are that you should verify before using this that $statement is a PDOStatement object, also we should probably take the strpos out of the substr statement in case strpos returns false, which would probably cause an error, finally, this only works with one word statement types, like SELECT, INSERT, etc and not multi-word statement types like ALTER TABLE
I have the following code in a CI app :
$query = "INSERT INTO user(user_name,user_email) VALUES(?,?)";
$result = $this->db->query($query,array($userName,$email));
if ($result->num_rows()>0)
return $this->db->insert_id();
else
return null;
This yields an error ; Fatal error: Call to a member function num_rows() on a non-object in C:\xampp\htdocs\cmdline\application\models\mlogin.php on line 38
line 38 is the condition for number of rows is greater than 0 .
Now I don't get what is happening - I am using CI's documentation to check whether number of rows is greater than 0 , why does this fail ?
It's because you're doing an INSERT query. Queries that modify data return TRUE in all cases, so what you're really attempting is TRUE->num_rows(), which doesn't make any sense, causing an error.
What you actually want to check is $this->db->affected_rows(), which will tell you how many rows were inserted into the database.
Although you're not doing it in this case, it's worth noting that affected_rows() will only return the count of rows that actually changed during the query, so UPDATE queries that don't actually modify data (i.e. if the field already has the value the query is trying to set it to), then that row won't be reflected in the affected_rows() value.
From CodeIgniter's documentation.
The query() function returns a database result object when "read" type queries are run, which you can use to show your results. When "write" type queries are run it simply returns TRUE or FALSE depending on success or failure. When retrieving data you will typically assign the query to your own variable, like this:
Your query, because it's an INSERT will simply return TRUE or FALSE.