PDO Replicating rows in different servers General Error - php

So I am trying to "move" selected rows from 1 table to another in different databases.
It in theory works (but if anyone wants to give any opinions please do, I am very new to PDO. I however keep getting a "SQLSTATE[HY000]: General error" error.
Any advice?
private function broken() {
try {
$sql = "SELECT * FROM `calls` WHERE `calls`.`status`=0 AND `calls`.`stage` < 4 AND `calls`.`answer` < (NOW() + INTERVAL 10 MINUTE)";
$query = $this->staging->query($sql);
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
// Insert in production database:
$sql = "INSERT INTO `ivr_incomplete` (`id`,`sip_id`,`extension`,`caller_id`,`stage`,`status`,`survey_id`,`start`,`answer`,`hangup`,`end`) VALUES (:id, :sip_id, :extension, :caller_id, :stage, :status, :survey_id, :start, :answer, :hangup, :end)";
$query = $this->production->prepare($sql);
$query->execute($row);
// Delete from staging:
$sql = "DELETE FROM `calls` WHERE `id`='".$row['id']."'";
$this->staging->query($sql);
}
}
catch(PDOException $e) {
$this->informer("FATAL", "Unable to process broken IVR surveys. Error: ".$e->getMessage());
}
}

Two points:
You are preparing the INSERT on every iteration, which sort of eliminates half of the point of using a prepared statement - all you are using it for is escaping. One of the points of prepared statements is that the query is only parsed once, so if you need to execute the same query repeatedly with different values, calling prepare() once and then simply calling execute() with the different data sets can significantly boost performance.
This whole thing could be accomplished in 2 queries: Removed due to use of two separate DB connections
EDIT
Try this code:
You will likely need to adjust the error handling to meet your needs, particularly around how it is handled if there is an error with an INSERT, since I doubt you would want to break the whole operation and leave the rows that have been successfully processed in the source table.
private function broken() {
try {
// Fetch records to move
$sql = "
SELECT *
FROM `calls`
WHERE `status` = 0
AND `stage` < 4
AND `answer` < (NOW() + INTERVAL 10 MINUTE)
";
$query = $this->staging->query($sql);
if (!$query) {
$errorInfo = $this->staging->errorInfo();
throw new Exception("MySQL error at SELECT: $errorInfo[1] ($errorInfo[0]): $errorInfo[2]");
}
// Prepare the INSERT statement
$sql = "
INSERT INTO `ivr_incomplete`
(`id`,`sip_id`,`extension`,`caller_id`,`stage`,`status`,`survey_id`,`start`,`answer`,`hangup`,`end`)
VALUES
(:id, :sip_id, :extension, :caller_id, :stage, :status, :survey_id, :start, :answer, :hangup, :end)
";
if (!$stmt = $this->production->prepare($sql)) {
$errorInfo = $this->production->errorInfo();
throw new Exception("MySQL error at prepare INSERT: $errorInfo[1] ($errorInfo[0]): $errorInfo[2]");
}
// A list of the row IDs we are working with
$rowIds = array();
// Loop the results and insert them
for ($i = 1; $row = $query->fetch(PDO::FETCH_ASSOC); $i++) {
if (!$stmt->execute($row)) {
$errorInfo = $stmt->errorInfo();
throw new Exception("MySQL error at INSERT row $i (id: {$row['id']}): $errorInfo[1] ($errorInfo[0]): $errorInfo[2]");
}
$rowIds[] = (int) $row['id'];
}
// Delete from staging:
if ($rowIds) {
$sql = "
DELETE FROM `calls`
WHERE `id` IN (".implode(', ', $rowIds).")
";
if (!$this->staging->query($sql)) {
$errorInfo = $this->staging->errorInfo();
throw new Exception("MySQL error at DELETE: $errorInfo[1] ($errorInfo[0]): $errorInfo[2]");
}
}
} catch(PDOException $e) {
$this->informer("FATAL", "Unable to process broken IVR surveys (PDO). Error: ".$e->getMessage());
} catch (Exception $e) {
$this->informer("FATAL", "Unable to process broken IVR surveys (MySQL). Error: ".$e->getMessage());
}
}

Related

PHP PDO prepare transaction statement (Two inserts)

I have tried to insert two insert intos through a transaction statement but it did not work. The console is giving me database errors. I have checked the documentation http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers and it is obvious I am missing something.
The goal is simply insert into two different tables different information. I tried the following:
// create record
function create(){
try {
$stmt->beginTransaction();
$query = "INSERT INTO " . $this->table_name . "
SET user_id = ?, ";
// prepare query statement
$stmt = $this->conn->prepare($query);
// bind values to be inserted
$stmt->bindParam(1, $this->user_id);
$stmt->execute();
$query2 = "INSERT INTO legalcases_report
SET user_id = ?, ";
// prepare query statement 2
$stmt = $this->conn->prepare($query2);
$stmt->bindParam(1, $this->user_id);
$stmt->execute();
$stmt->commit();
return true;
} catch (Exception) {
$stmt->rollBack();
return false;
}
}
There are lots of problems in this code, I hope I can catch them all
// create record
function create(){
try {
// transaction work on a connection and not a statement
//$stmt->beginTransaction();
$this->conn->beginTransaction();
// Incorrect syntax for an INSERT command
// Error - Trailing comma in sytax
$query = "INSERT INTO " . $this->table_name . "
SET user_id = ?, ";
// prepare query statement
$stmt = $this->conn->prepare($query);
// bind values to be inserted
$stmt->bindParam(1, $this->user_id);
$stmt->execute();
// Incorrect syntax for an INSERT command
// Error - Trailing comma in sytax
$query2 = "INSERT INTO legalcases_report
SET user_id = ?, ";
// prepare query statement 2
$stmt = $this->conn->prepare($query2);
$stmt->bindParam(1, $this->user_id);
$stmt->execute();
// commit also works on a connection object
//$stmt->commit();
$this->conn->commit();
return true;
// PDO generates a PDOException so you should really catch that,
// it will fallback to the parent Exception object, BUT
// there may be times when you want to catch them seperately
// from the same try block, so use the correct one or both
} catch (PDOException $pex) {
$this->con->rollback();
$pex->getMessage();
exit; // because you have a serious problem
// or throw your own exception to the calling code
throw new Exception('Create user failed ' . $pex->getMessage());
}
}
Incorrect syntax for an INSERT command
The PHP PDO manual
I guess you should use PDO object, not PDOStatement:
try {
$this->conn->beginTransaction();
...
$this->conn->commit();

SQL prepared statements - how to SELECT multiple rows

I have this code so far
// Starts the transaction
self::$database->startTransaction();
try {
$sql = "SELECT playerId FROM players WHERE name=?";
$stmt = self::getConnection()->prepare($sql);
$stmt->bind_param('s', $playerName);
foreach ($playerNames as $key => $playerName) {
$stmt->execute();
$stmt->bind_result($playerId);
$stmt->fetch();
echo $playerId . "<br>";
}
// commits the transaction
self::$database->commit();
} catch (Exception $e) {
self::$database->rollback();
throw new Exception(__METHOD__." | ".$e->getMessage());
}
The array $playerNames contains the names of the players, e.g.
array('Player1', 'Player2', 'player3')
The code from above should select the playerId of those players from the database. I have some issues:
It just returns the last playerId (in this case the Id of 'player3'). I don't know why.
I use a foreach-loop to execute(). is this bad for the performance, if there were hundreds of names in the array?
In generell: Is this the correct approach for SELECTing or INSERTing stuff from or into a database?
I read this question: How can I prevent SQL injection in PHP?
But it didn't really work because of this:
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
I get an error with the getResult()-method. It says, the method doesn't exist. I think my webspace doesn't support it and I can't install it manually. So I need to stick with fetch().
Or might it have other reasons?
$sql = "SELECT playerId FROM players WHERE name=?";
$stmt = self::getConnection()->prepare($sql);
$stmt->bind_param('s', $playerName);
$stmt->bind_result($playerId);
foreach ($playerNames as $key => $playerName) {
$stmt->execute();
$stmt->fetch();
echo $playerId . "<br>";
}
You are fetching results of only last execute
Running long loops is apparently bad for performance. Try to avoid them.
Yes, in general.

Second prepared statement is not firing

thanks for your time.
Below I have two prepared statements, query & query2;
con is the connection var
The first query is running perfectly and updating the database.
The second query is not updating anything, although it is not giving any error.
When I look at the second query that is logged after a "successful" run, the inserted variable is looking like an empty string. i.e. RESTI=''
Why is this happening? Is my code in the right order for the second query to run?
$row = 1;
$con=mysqli_connect("connect info");
if (mysqli_connect_errno())
{
//echo "Failed to connect to MySQL Error 1: " . mysqli_connect_error();
//error reporting done here
}
else
{
$con->autocommit(false);
$query = $con->prepare("UPDATE table where `INDEX`=?");
$query2 = $con->prepare("UPDATE table2 where (SELECT column from table where`RESTI`=?)");
$query->bind_param('i', $row);
$query2->bind_param('i', $row);
if($query->execute() == false)
{
//Failed!
/ERROR HANDLING
}
else
{
//SUCCESS
}
if($query2->execute() == false)
{
//Failed!
/ERROR HANDLING
}
else
{
//Success
}
$con->commit();
$query->close();
$query->close();
}
mysqli_close($con);
Here is how your update statement should be:
"UPDATE table SET column=<new value to set> WHERE INDEX=?"
"UPDATE table2 SET <col to update>= (SELECT column from table where`RESTI`=?) WHERE condition
Make sure RESTI is an unique field and the subquery would only return scalar value

Why do I get error SQLSTATE42000 in PHP/MySQL

I am working on a project using PHP and MySQL.
I have an HTML table that has 3 columns into which I load data from my "Tasks" table in MySQL. The columns are: id, taskname and a button column that when clicked on, takes you to the Edit page for the relevant task (I pass the task id as a URL) - http://localhost/tasks/?edit&id=3
The problem arises when I try to load the details about this task. This is the code:
if(isset($_GET["id"]))
{
try
{
$sql = "SELECT * FROM tasks WHERE id = :id";
$result = $pdo->prepare($sql);
$result->bindValue(":id", $_GET["id"]);
$result = $pdo->query($sql);
}
catch(PDOException $e)
{
$error = "Error trying to load task - " . $e->getMessage();
include "error.php";
exit();
}
foreach($result as $task)
{
$tasktext = $task["task"];
$id = $task["id"];
}
$title = "Edit task";
$action = "edittask";
$button = "Edit task";
include 'form.php';
exit();
resetParameters();
I get the following error:
Error trying to load task - SQLSTATE[42000]: Syntax error or access violation: 1064 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 ':id' at line 1
When I replace the WHERE id = :id with WHERE id = 3 for example it works and loads the details about the task however I simply cannot get it to load the details about the task I have clicked on in the previous screen.
Could anyone spot anything wrong with my code/logic and point me in the right direction please?
You need to use execute() not query() when using prepared query's:
execute() PDOStatement::execute — Executes a prepared statement.
query() PDO::query — Executes an SQL statement.
Try:
<?php
try
{
$sql = "SELECT * FROM tasks WHERE id = :id";
$query = $pdo->prepare($sql);
$query->bindValue(":id", $_GET["id"]);
$query->execute();
$result = $query->fetchAll(PDO::FETCH_ASSOC);
}
catch(PDOException $e)
{
$error = "Error trying to load task - " . $e->getMessage();
include "error.php";
exit();
}
?>

Getting the last inserted messages from ajax chat

I'm building a chat application and having some issues. First of all I want the chat starts loading from database once the the user logs in.
function that gets the whole chat from db which is called by ajax
function getChatData(){
global $mysqli;
//echo $lastinseted= $mysqli->insert_id();
$sql = "SELECT `chat`.`message`,
`users`. `username`,
`chat`.`timestamp`
from `chat` JOIN `users` ON (`chat`.`user_id`=`users`.`user_id`)
ORDER BY `chat`.`timestamp` DESC limit 15";
try{
if($stmt=$mysqli->prepare($sql)){
echo returnJson($stmt);
$stmt->close();
$mysqli->close();
}else{
throw new Exception("An error occured while fetching record data");
}
}catch(Exception $e){
log_error($e, $sql, null);
echo 'fail';
}
}
here is the callback function:
function getChatCallback(data){
var h='';
for(var i=0, l=data.length;i<l;i++){
h+=data[i].username+' says: '+data[i].message+'<span style="color:gray"> at the time '+data[i].timestamp+'</span><br/>';
}
$('.messages').html(h);
setTimeout(getChat,1500);
}
this is the function that will insert the new messages to the database which is called once the user hits enter and it is called also by ajax call:
function putChatData($message,$room,$user_id){
global $mysqli;
$sql = "INSERT INTO `chat`
(`message`,`timestamp`,`room`,`user_id`)
VALUES (?,?,?,?)";
$timestamp = gmdate("Y-m-d H:i:s");
try{
if($stmt=$mysqli->prepare($sql)){
$stmt->bind_param('ssii',$message,$timestamp,$room,$user_id);
$stmt->execute();
$stmt->close();
$mysqli->close();
}else{
throw new Exception("An error occured while fetching record data");
}
}catch(Exception $e){
log_error($e, $sql, null);
echo 'fail';
}
}
the problem now is that I could insert the new messages to the db, but the first function the gets the chat, brings all that chat including the old ones before the user logs in. I tried to use timestamp or the last insert id but didn't work with me.
For this usecase you need to know the reg time and add a WHERE condition to your query
$sql = "SELECT `chat`.`message`,
`users`. `username`,
`chat`.`timestamp`
from `chat` JOIN `users` ON (`chat`.`user_id`=`users`.`user_id`)
WHERE `chat`.`timestamp` > $userRegDate
ORDER BY `chat`.`timestamp` DESC limit 15";

Categories