Unbuffered queries error - how to get them on localhost - php

Sometimes I'm getting this error (on remote server only):
General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll()...
I added this line on top of my php code - without success:
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute;
Two questions:
How to properly avoid this error, if possible without using fetchAll()?
What should I do to get this error on my localhost, if the error exists?
I'm on Windows 7, xampp, phpmyadmin...
here is the code
$st = $db->query("select title from folders where id = " . $_GET['fd'] . " limit 1");
$st->execute();
$title = $st->fetchColumn();
$stb = $db->query("select * from arts where folder = " . $_GET['fd'] . " order by ind asc");
error is on the last line

Simple answer
Create a new (additional) connection.
Once your in the middle of an un-buffered request that connection is locked/block up. Pretty much unusable.
Or don't do it (while the buffered query is on-going).
So if you need to query other things, either do that before the unbuffered part, or open a second buffered (normal) connection to the DB.
I once pulled 140 million rows out of the DB with an un-buffered query. Now they are in MongoDB (even though I have mixed feelings about this). PS. if anyone knows how to improve mongo's count performance I am all ears.
You only really need un-buffered query if your working with a Large dataset, and I mean > 500k rows. I use it as a last resort.
Anyway, good luck. It's a pain.
Update
For you case, you need to make the PDOStatement object go away or call PDOStatement::closeCursor.
$st = $db->query("select title from folders where id = " . $_GET['fd'] . " limit 1");
$st->execute();
$title = $st->fetchColumn();
unset($st); //<---- unset the statement object
$stb = $db->query("select * from arts where folder = " . $_GET['fd'] . " order by ind asc");
If I am thinking about it right, that unset should take care of it. Normally this happens when it goes out of scope such as the end of a method or function and no reference to it. This is sort of like free_result or whatever it was for Mysqli
I just assumed you had something like this:
$st = $db->query("select title from folders where id = " . $_GET['fd'] . " limit 1");
$st->execute();
foreach($st->fetchColumn() as $col){
$stb = $db->query("select * from arts where folder = {$col} order by ind asc");
}
Where you were using the results of an open Query for a new query. Which is a no-no. In a case like above the only thing you can do is open a new connection for the part in the loop as it may not be possible to do it all in one Query (for whatever reason).
In any case change this to proper prepared statements:
$st = $db->prepare("select title from folders where id = :id limit 1");
$st->execute(['id' => $_GET['fd']]);
As it is your vulnerable to SQLInjection. It's very easy to fix in PDO, and it's very bad to not do it.
Cheers!

Related

commands are out of sync.. you cant run this command now in while loop

`$sql = "call geodist(".$_SESSION['This'].",500)";` //get the ids near you
$result=mysqli_query($GLOBALS['link'],$sql) or die(mysqli_error($GLOBALS['link']));
while($row=mysqli_fetch_assoc($result)) // insert them into nerby table
{
$sql = "INSERT INTO `nearby`(`userid`, `strangerid`) VALUES (".$_SESSION['This'].",".$row['id'].")";
mysqli_close($GLOBALS['link']);
mysqli_query($GLOBALS['link'],$sql)
or die("akash".mysqli_error($GLOBALS['link']));
}
when i remove the '//*' statements i get out of sync error.... keeping those two lines help me run my code but code becomes slow since for every loop iteration the database connection is closed and reopened. pls tel me an alternate.... i will really be grateful to you
What happens is you have data in the buffer between mysql and PHP when you try to fill it with new data (the query inside the loop).
What you need to do is
either fetch all data from the buffer before you use it for other query
See how u set this mysqli connection to fetch data unbuffered.
Read more here
http://dev.mysql.com/doc/apis-php/en/apis-php-mysqlinfo.concepts.buffering.html
DROP TEMPORARY TABLE IF EXISTS near;
CREATE TEMPORARY TABLE near
i added these 2 lines in my geodist() procedure.
it creates a temporary table named "near" and stores the result set in it.
now this table could be used as follows
$sql = "call geodist(".$_SESSION['This'].",".$GLOBALS['RADIUS'].")"; // get the ids near you
$result=mysqli_query($GLOBALS['link'],$sql) or die(mysqli_error($GLOBALS['link']));
$sql = "SELECT m.`id`\n"
. " FROM `members` m , `already_assigned` a\n"
. " WHERE a.`id`=m.`id` and m.`id` <> ".$_SESSION['This']."\n"
. " and m.`gender`=".$_SESSION['wants']." and m.`interested_in`=".$_SESSION['gender']." and a.`status`='free'\n"
. " and m.`id` IN (SELECT * from `near`)\n" /*see this line*/
. " ORDER BY RAND( ) \n"
. " LIMIT 1";
you can see that now i have removed the while loop... now its not required
How 'bout not closing the database connection until you're actually done with it?
You should only ever establish ONE connection to any given database server (so basically, one connection in your script unless you're working with a complex multi-DB-server setup)

Increment int value in MySql

I am trying to get a value of an int from a field in a MySql database and increment it by 1 when a new record is added. What is happening, is that when the record is inserted it is placing a 1 and not adding one to the value of the field. For example, in the last record, the value is 10 so after running the query the value should be 11.
I am struggling to see why this is not working and would be grateful if someone could offer any advice as to how to amend my code to a working solution. Many thanks
php code
function get_ref(){
$query = "SELECT MAX(`id_usr`) AS `max` FROM `user_usr`";
$result = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_assoc($result);
$max = $row['max'];
$sql = 'select idcom_usr'
. ' from user_usr'
. " where id_usr = '$max'"
. ' order '
. ' by id desc'
. " limit 1";
$result = mysql_query($sql);
$ref = mysql_result($result,0,"idcom_usr");
return $ref + 1;
}
You can have the column auto incrementing. This way you offload the work from PHP to MySQL, which is always a good thing.
Oh yeah, and Please, don't use mysql_* functions in new code. They are no longer maintained and are officially deprecated. See the red box? Learn about prepared statements instead, and use PDO or MySQLi - this article will help you decide which. If you choose PDO, here is a good tutorial.
You can try to achieve your goal using a trigger
CREATE TRIGGER tg_user_usr_insert
BEFORE INSERT ON user_usr
FOR EACH ROW
SET NEW.idcom_usr = (SELECT COALESCE(MAX(idcom_usr), 0) + 1 FROM user_usr);
Then when you insert new rows
INSERT INTO user_usr (idcom_usr) VALUES (0),(0);
Values for idcom_usr will be assigned by the trigger.
Here is SQLFiddle demo.
Even if for some reason you do it in php instead of two queries you need only one
SELECT COALESCE(MAX(idcom_usr), 0) + 1 next_value
FROM user_usr
Note: this approach is prone to errors under heavy load due to concurrency.

Efficiently getting number of rows returned of SELECT query with WHERE clause using PDO

There are numerous discussions on SO regarding how to get the number of rows returned when running a SELECT query using PDO. While most (including the PHP manual) suggest using two queries, with the first running COUNT(), I haven't seen one that suggested how to easily do this using prepared statements with WHERE clauses.
How do I most-efficiently (both in processing and number of lines of code) run a COUNT() using the same WHERE clause? The prepared query already has the columns specified. fetchAll() won't work here because that won't scale; if I have to return millions of rows, processing it using fetchAll would be super slow.
For example, without the count:
$sql = "SELECT
FirstName,
LastName
FROM
People
WHERE
LastName = :lastName";
$query = $pdoLink->prepare($sql);
$query->bindValue(":lastName", '%Smith%');
$query->execute();
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
echo $row['FirstName'] . " " . $row['LastName'];
}
I looked at just adding COUNT(ID) to the SELECT clause, and having it be just one query, but it looks like there is no real good way (or not database-specific way) of rewinding the fetch() once I get a row from it.
Another solution could be making the WHERE clause it's own variable that is built. But, that doesn't seem very efficient. It's preparing two queries, binding the values all over again, and executing it.
So something like:
$whereClause = " WHERE
LastName = :lastName";
$rowsSql = "SELECT
COUNT(ID) As NumOfRows
FROM
People " . $whereClause;
$rowsQuery = $pdoLink->prepare($sql);
$rowsQuery->bindValue(":lastName", '%Smith%');
$rowsQuery->execute();
if ($rowsQuery->fetchColumn() >= 1)
//Prepare the original query, bind it, and execute it.
$sql = "SELECT
FirstName,
LastName
FROM
People " . $whereClause;
$query = $pdoLink->prepare($sql);
$query->bindValue(":lastName", '%Smith%');
$query->execute();
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
echo $row['FirstName'] . " " . $row['LastName'];
}
}
else
{
//No rows found, display message
echo "No people found with that name.";
}
When using MySQL, PDOStatement::rowCount() returns the number of rows in the result set. It actually calls the underlying mysql_num_rows() C function to populate the value. No need for multiple queries or any other messing around.
This is true of MySQL, but this behaviour cannot be relied on for other drivers (others may support it but it's not guaranteed, I'm not familiar with others enough to say for sure either way). But since your question regards specifically MySQL, it should serve your purposes.
Try this built-in PDO function;
$query->rowCount();

Print out num rows only selecting user2_id's

I'm trying to print out only the number of rows containing user2_ids within my streamdata_feedback table and it seems to be printing out both the user2_id and the user1_id. How can I rectify this issue with the below code?
$user1_id=$_SESSION['id'];
$user2_id=$data['id'];
$likesqltwo = "SELECT *
FROM streamdata_feedback
WHERE feedback_rating = 1
AND feedback_userid = " . $user2_id .
"AND feedback_streamid = " . $streamid;
$likequerytwo = mysql_query($likesqltwo);
$num3 = mysql_num_rows($likequerytwo);
if ($num3 > 0)
{
echo "And <a title = 'See who likes " .
$poster_name['fullusersname'] .
"s status' href='include/likes.php?streamitem_id=" .
$streamitem_data['streamitem_id']."' />" .
$num3 . " ";
}
Do you have a client for your MySQL database? I'd recommend picking up SqlYog Community Edition. You can then execute your query against it and see how many rows are returned outside of PHP code. Once you have a satisfactory query, then incorporate it into your PHP project.
Next tip: You can include variables from PHP directly in strings with double quotes. PHP will parse the variable, and you needn't concatenate. For example:
$likesqltwo =
"SELECT *
FROM streamdata_feedback
WHERE feedback_rating = 1
AND feedback_userid = $user2_id
AND feedback_streamid = $streamid;";
However this code still has a potential flaw, and that's SQL injection attacks. So ensure that the variables you include are not coming from users, or follow the link to learn more about preventing such things. That's not what you asked for help on, but I thought it was worth a mention.
To find out how many times the feedback_userid equals $user2_id for a particular feedback_streamid and for only feedback_rating values of 1, you could try the following query:
SELECT COUNT(id)
FROM streamdata_feedback
WHERE feedback_rating = 1
AND feedback_userid = 123
AND feedback_streamid = 456;
Substitute your primary key for id, and the correct user id and stream id for 123 and 456 respectively. If you get an unexpected number of results, I recommend removing COUNT(id) and selecting the columns of interest so you can inspect and see why you're getting more rows than you thought.

MySQL Update Fix Two rows with one query

This is the code giving me issue - I'm trying to update multiple records with one insert. The values are put in an array and using a foreach I've prepared the mysqli update. But it's not working. Just gives a MySqli error about the syntax on the update.
foreach($users as $user){
if(empty($course)) continue;
$query_string .= " SET group_id='$group_id' WHERE user_id='".$user."'; ";
}
$query_string = substr($query_string,0,-1);
$query = "UPDATE users" . $query_string;
$result = mysqli_query($dbc, $query) or trigger_error("Query: $query");
The error it gives is:
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 'SET group_id='10' WHERE user_id='5''. I think it's the ';' in the middle that mysqli isn't accepting.
Assuming you've got more than one user, your query will look like
UPDATE users SET ... SET ... SET ... SET ...
which is incorrect. You cannot do updates to multiple rows in this fashion. Either do multiple queries, each updating one student, or you'll have to build a huge case/if block to do this in a single query.
You'd be better off doing the multiple queries, as you'll probably spend more time BUILDING the monolithic query than it'd take to run the individual updates.
How about WHERE...IN
UPDATE foo SET bar = 0 WHERE baz IN (1,2,3,4,5,6)
(presuming that you are setting them all to the same group ID, which is not clear in the context provided)
try this code:
<?php
$queries = array();
foreach($users as $user){
if(empty($course)) continue;
$queries[] = "update users set group_id = '" . mysql_real_escape_string($group_id) . "' where user_id = '" . mysql_real_escape_string($user) . "'";
}
array_map('mysql_query', $queries);
?>
Your problem is that you don't separate the different users with ;. Since you're updating all users to have the same group (I'm not sure this is the case, otherwise it will get much more complex) you can simply expand the criteria with OR. Your resulting query would look something like the following:
UPDATE users SET group_id='42' WHERE user_id='1' OR user_id='2' OR user_id='3';
Another solution would be to use WHERE ... IN. Here's an example of that:
UPDATE users SET group_id='42' WHERE user_id IN (1, 2, 3);

Categories