The below php code runs a query for which i get $res = true which means that the query should have run.
I checked the health of the PDO object also to make sure and found out that other queries get run correctly.
Also no exception were caught. Have run out of ways to solve this issue.
function insertPaypalSavedSanity($udi, $isPaypalSaved){
global $DBH;
try {
$sql = "INSERT INTO sanity(user_id, saved_paypal_used_previously) VALUES(:user_id,:sv) ON DUPLICATE KEY UPDATE saved_paypal_used_previously=:sv";
$sqlcon = $DBH->prepare($sql);
$res = $sqlcon->execute(array(
'user_id'=>$_SESSION['userID'],
'sv'=>$isPaypalSaved));//$res is true after executing the query
$x = 1;// I put the debugger at this point and run other queries with my PDO object($DBH)
} catch(Exception $e)
{
logger ("sanity queries",$e->getMessage());
}
}
This got solved by adding start transaction to beginning of statement and commit to the end of statement. I still have no clue as to why this worked.
Related
I have something like the following, in a function that deletes both the files and db entries:
$adapter = $this->getAdapter();
$query = $adapter->query("call find_results_by_job_id(?)", array($jobId));
$items = array();
while (($current = $query->current()) !== false)
{
$id = $current['id'];
$items[] = $id;
$query->next();
}
$this->deleteFromDataStore($items);
$result = $adapter->query("call delete_results_by_job_id(?)", array($jobId), \Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);
(Some of that might not look like the best way to do it, because I simplified it for this example)
I'm getting this error on the last line: SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.
I'm assuming that the problem is because the query/adapter hasn't closed the connection from iterating results yet when I try to execute another statement. If that is the case, how can reuse the adapter, or close the query, or whatever I have to do before the last line?
The strange part is that code following almost exactly this same pattern works in another method.
Answer:
When using the PDO driver, $query->getDataSource()->getResource()->closeCursor(); fixes it
Seems like you are using an unbuffered query in MySQL.
If it is so, you will either have to turn buffering on or break execution of previous query which seems to hang?
Something like $query->close()
EDIT:
If $query is instance of StatementInterface, then there is getResource() which returns mysqli_stmt and you can call close() on it.
EDIT2: (to incorporate final resolution)
In case it uses PDO, you can get PDOStatement and call closeCursor()
Assuming you have the result of a query in your hands and you dont know whether it is a ResultSet or a Result, the following will do the job.
Tested as of Zend Framework 3.
use Zend\Db\ResultSet\ResultSet;
...
public function closeResult( $result )
{
if( is_a($result, ResultSet::class) )
{
$stmt = $result->getDataSource()->getResource();
}
else
{
$stmt = $result->getResource();
}
$stmt->closeCursor();
}
$this->adapter
->query($sql)
->execute()
->getResource()
->fetchAll(\PDO::FETCH_ASSOC);
First of all I'm new in web development so sorry if its a dumb question,I have an array, that the keys of the array are the id of the records that need to be updated in the database, i came with the bellow code to create the query and using mysql transaction to run the query (since few records should be updated together). the generated query works fine when i run it using command line, but with php code NO!
The code to generate the query :
$insert="";
if($run==true){
foreach($result as $key=>$x){
$insert = $insert ."update project set type='".$x."' "."where "."id=".$key.";";
}
//echo $insert;
$insert=$insert ."COMMIT;";
$insert= "START TRANSACTION;". $insert;
The result of the code:
START TRANSACTION;update project set type='project1' where id=1;update project set type='project2' where id=2;COMMIT;
The error that it gives me:
Error: 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 'update project set type='project1' where id=1;update project set type='project2'' at line 1
I did not include the sql connections and... since i believe in high percentage they are fine, but in case its necessary i can include them too.
Thanks in advance
Multiple queries are not supported using MySQL functions. You would need to break down the transaction:
$sql1 = UPDATE `project` SET `type`='project1' WHERE `id`=1;
$sql2 = UPDATE `project` SET `type`='project2' WHERE `id`=2;
You can however use mysqli_mutli_query or as mentioned in another answer PDO
You might want to switch to PDO which has an interface to transactions directly.
$db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("update project set type= ? where id= ?");
$db->beginTransaction();
try {
foreach ($result as $key => $x) {
$db->execute(array($x, $key));
}
$db->commit();
} catch (PDOException $e) {
$db->rollBack();
throw $e;
}
I have this problem that drives me crazy. All i want is just check a query for an error, if so display error, otherwise run the query.
I have the following almost (since it runs the insert query twice) working
[..]
$dbdata = new mySQLAccessData();
$db = new PDO($dbdata->hostname,$dbdata->username,$dbdata->password);
$defaults = new Defaults();
[..]
if(!$db->exec($sql)){
echo($defaults->throwError('MySql error',implode(":",$db->errorInfo())));
}else{
$db->exec($sql);
$defaults->writeLog($table,$db->lastInsertId(),'add');
}
I tried numerous things (amongst others the try(){}catch(){} method) but nothing worked except for the code above. It shows the error the way i want, and only when an error occurs, but runs the exec() twice...
Can someone bail me out?
Why do you want to execute the query again in the else part? Usually you just try to run the query and if errors happen, react on them.
[..]
$dbdata = new mySQLAccessData();
$db = new PDO($dbdata->hostname,$dbdata->username,$dbdata->password);
$defaults = new Defaults();
[..]
if(!$db->exec($sql)){
echo($defaults->throwError('MySql error',implode(":",$db->errorInfo())));
}else{
$defaults->writeLog($table,$db->lastInsertId(),'add');
}
As far as I know, there is no option to "test" a query before actually executing it.
If you want to see an exception thrown when an error occurs, just set the PDO error-mode (see also: Connections and Connection management):
$db = new PDO($dbdata->hostname,$dbdata->username,$dbdata->password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
This for example will make your code throw exceptions automatically. Probably exactly what you're looking for.
The actual issue with your code is doing exec twice. You don't need to:
$success = $db->exec($sql);
if (!$success) {
echo $defaults->throwError('MySql error', implode(":", $db->errorInfo()));
} else {
# do not exec *again* here.
$defaults->writeLog($table, $db->lastInsertId(), 'add');
}
I managed to run the following code to insert into my table on first try. Then, I deleted that row in PHPMyAdmin to test my code further. I also noticed that it didn't get deleted on the 1st try. Only after few try. This might be due to I didn't set the $pdoHandle to NULL after I'm done with the query.
Then, unfortunately I couldn't insert new row on subsequent run. I even tried to change the input value and to avail I was unable to insert new row. The following are my PHP codes:
public function CreateNewCustomer($userId,$password,$name,$email)
{
$userId = filter_var($userId,FILTER_SANITIZE_STRING);
$password = filter_var($password,FILTER_SANITIZE_STRING);
$password = sha1($password);
$name = filter_var($name,FILTER_SANITIZE_STRING);
$email = filter_var($email,FILTER_SANITIZE_EMAIL);
do{
$customerId = hexdec(bin2hex(openssl_random_pseudo_bytes(4,$isStrong)));
echo $customerId;
$result = $this->connObject->exec("SELECT COUNT(id) FROM customer_tbl WHERE id=$customerId");
var_dump($result);
}while($result>0);
$statement = $this->connObject->prepare("INSERT INTO customer_tbl (id,name,email) VALUES ($customerId,:name,:email)");
$result = $statement->execute(array(':name'=>$name,':email'=>$email ));
var_dump($result);
$statement = $this->connObject->prepare("INSERT INTO login_tbl (username,password,customer_id) VALUES (:userName,PASSWORD(:password),$customerId)");
$result = $statement->execute(array(':userName'=>$userId,':password'=>$password ));
var_dump($result);
}
I used the following code to access the above method.
function Test($userName,$password,$name,$email)
{
try
{
$dbConnect = new DbConnect();
$pdoHandle = $dbConnect->Connect();
$userAccess = new UserAccess($pdoHandle);
$userAccess->CreateNewCustomer($userName,$password,$name,$email);
}
catch(PDOException $e)
{
$pdoHandle = null;
var_dump($e);
}
$pdoHandle = null;
}
Test('tester','password','TestX','test#example.com');
The var_dump of results is always false.
Is there any problem with my codes or is it something wrong with the database?
UPDATE/SOLUTION:
I just read through the PHP document on PDO::exec() and one of the user contributed notes mentioned that you can't use any SELECT statements (even thou the above only returns the count value) and any statements which might return a rows. The return value of PDO::exec() is the number of affected rows (integer), so the PDOStatement::closeCursor() can't be used to solve it. Even when I set the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>true, it still doesn't work.
So, don't use PDO::exec() for any SELECT. I changed my code to PDO::query() instead as below,
do{
$customerId = hexdec(bin2hex(openssl_random_pseudo_bytes(4,$isStrong)));
$statement = $this->connObject->query("SELECT COUNT(id) FROM customer_tbl WHERE id=$customerId");
$statement->execute();
}while($statement->fetchColumn(0)>0);
Hope this would be helpful to anyone looking for a solution with similar problem and always remember to read the PHP document first including the user contributions.
Maybe not the answer but here are some things that you can do if you cannto see an obvious error:
If execute returns false, you can get more information about the error that happened by:
$arr = $statement->errorInfo();
print_r($arr);
or you can set different error reporting modes (e.g. throw an exception instead of the defaultsilent mode):
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
This should help you to find the "real" error.
As it turned out (see comments below question), in this case the real error was:
"Cannot execute queries while other unbuffered queries are active.
Consider using PDOStatement::fetchAll(). Alternatively, if your code
is only ever going to run against mysql, you may enable query
buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY"
In this case you have 2 options:
you can set the option to use buffered queries
$dbh = new PDO(’mysql:host=localhost;dbname=test’, ‘root’, ” ,array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true))
or change your code and close an open cursor (may depend on the db driver you are using). You always should read the documentation which covers a lot of default problems.
Hope this helps.
I'm assuming the method is inside the UserAccess class and the connection you pass in is set to the local $this->connObject.
I suspect after you deleted the record, $customerId is being set to null in your interesting do-while loop with the select statement. If the id column in the DB is a non-null primary key field and you try to insert an explicit null it will fail.
Also, no need to keep setting your DB connection to null... this isn't C and connections aren't persistent (unless you explicitly declare them as such).
Are prepare() and transactions mutually exclusive? I've got a lot of queries that I build and then execute, so it sounds like using a transaction is what I want; but I read on the prepare.statment page that using the bindParam method eliminates SQL-injection. Is there some way to do both?
Here's an example of the code I have right now (which may or may not be correct):
$dbhost=FOO;
$dbuser=FOOBAR;
$dbpass=RABOOF;
$options=array(STUFF);
$dbh = new PDO("mysql:host=$dbhost", $dbuser, $dbpass, $options);
// I know this ^ works
$dbh->beginTransaction();
$record_data = $dbh->prepare("UPDATE $db.$tbl SET :column=:value WHERE `key` = :key;");
function record_data($q,$a,$k){
$record_data->bindParam(':column', $q);
$record_data->bindParam(':value', $a);
$record_data->bindParam(':key', $k);
$record_data->execute();
}
// $pairs is an array with ~50 objects/rows
foreach($pairs as $pair){
list($qstn , $ans) = explode('=', $pair);
switch($qstn){
case 1: if(something) record_data($qstn,$ans,$key); break;
case 2: if(something) record_data($qstn,$ans,$key); break;
case 3: if(something) record_data($qstn,$ans,$key); break;
// more
default: record_data($qstn,$ans,$key); break;
}
}
$dbh->commit();
When I tried out the full code, I got No connection could be made because the target machine actively refused it. Usually I see a message like that when my connection info is wrong (or the account isn't set up properly/as I expect). But I tested the PDO connection separately and it worked fine. So I probably did something else wrong.
EDIT: Are variables allowed in prepare()?
EDIT 2: I added try{} around the $dbh = PDO(…) and added echo "connected" at the end of the try (and did the catch bit), and it echo'd "connected", so it is connecting. But after "connected" it prints that error message, so the issue is happening after a successful connection.
EDIT 3: I added
$dbRS = $dbh->query("SELECT * FROM `database`.`table`;");
$row = empty($dbRS) ? false : $dbRS->fetch(PDO::FETCH_ASSOC);
print_r($row);
and it printed the first row of the table, so for sure it's connecting.
"Are mutually exclusive?": No, as you show, is a kind of "function declaration", and transaction is like a (OS) process where the function runs.
"Are variables allowed?": I think you must start checking your PHP function record_data($q,$a,$k): there are a error. Try add global $record_data; at the begin of the function.
General comments: the main advantage of PDO is to capture errors (by PHP error line or returning SQL error messages) for each single SQL statment.
See pdo.begintransaction, pdo.commit, pdo.rollback and pdo.error-handling.
Example:
$dbh->beginTransaction();
/* Do SQL */
$sth1 = $dbh->exec("CREATE TABLE xyz (..)");
$sth2 = record_data($qstn1,$ans1,$key1);
$sth2 = record_data($qstn2,$ans2,$key2);
/* Commit the changes */
$dbh->commit();
You are using vars that were not defined in the scope of the function. Simply use:
global $record_data;
as the first line in the function and it will work.