MySql transqactions with dependent queries - mysql

I really hope you can help!
I use the following function to send a message in my PHP/MySql application:
public function sendMail($sender_id, $recipient_id, $subject, $message) {
$q = "INSERT INTO MAIL_MESSAGE (subject, message, date) VALUES ('$subject', '$message', NOW() )";
$s = mysql_query($q);
if (mysql_affected_rows()==1) {
$message_id = mysql_insert_id();
$q = "INSERT INTO MAIL (user_id, sender, message_id) VALUES ('$recipient_id','$sender_id','$message_id')";
$s = mysql_query($q);
if (mysql_affected_rows()==1)
return true;
}
return false;
}
I use two tables (MAIL_MESSAGE and MAIL) becuse the same '$sender_id' can send the same message to multiple '$recipient_id'.
Now the problem is that if the last query fails I have a row in MAIL_MESSAGE without the correspondent row in MAIL.
How can I solve this?
Transactions can help, but I don't know how to make it work!
Thanks in advance for your help.

Add "begin" at the start of the sequence to start a transaction. Commit the transaction only if both inserts succeed, otherwise rollback the transaction.
I do not know PHP, but based on your sample it would look something like the following:
public function sendMail($sender_id, $recipient_id, $subject, $message) {
$s = mysql_query("begin");
$q = "INSERT INTO MAIL_MESSAGE (subject, message, date) VALUES ('$subject', '$message', NOW() )";
$s = mysql_query($q);
if (mysql_affected_rows()==1) {
$message_id = mysql_insert_id();
$q = "INSERT INTO MAIL (user_id, sender, message_id) VALUES ('$recipient_id','$sender_id','$message_id')";
$s = mysql_query($q);
if (mysql_affected_rows()==1) {
$s = mysql_query("commit");
return true;
}
$s = mysql_query( "rollback" );
return false;
}

Related

Want to convert a function from Mysql to PDO

function get_country($code){
$query = mysql_query("SELECT country FROM `list_countries` WHERE `code`='".$code."' LIMIT 1");
$country = mysql_fetch_array($query);
return $country['country'];
}
Very new to PDO and have absolutely no idea how to turn this from a mysql function to a PDO one. Any help would be appreciated :)
You need to take PDO database connection handler with you :) From your code I would suggest setting it as global, or you can add additional parameter to all the functions.
$dbconn = new PDO("mysql:host=localhost;dbname=your_db","your_user","your_password");
// this line is important - throw an exception if there is an error
$dbconn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
function get_country( $dbconn, $code ) {
$res = $dbconn->prepare('SELECT country FROM `list_countries` WHERE `code`=? limit 1');
$res->execute( array( $code) )
$country = $res->fetch();
return $country['country'];
}

Laravael4 db raw query using ON DUPLICATE KEY UPDATE drops error

I'm really fighting with a laravel ON DUPLICATE KEY UPDATE query I can't get it to work, so the query basically looks like
foreach ($queries as $query) {
$update_time = array('update_time' => date('Y-m-d H:i:s'));
$query = array_merge($update_time, $query);
$keysString = implode(", ", array_keys($query));
$indexes = "";
$values = "";
$updates = "";
foreach ($query as $i=>$v){
$values .= ':'.$v.',';
$updates .= $i.'="'.$v.'",';
}
//$holder = rtrim(str_repeat('?,', count($query)),',');
$updates = rtrim($updates,',');
DB::statement("INSERT INTO products ({$keysString}) VALUES ({rtrim($values,',')}) ON DUPLICATE KEY UPDATE {rtrim($updates,',')}")
}
but I get
SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters
How do I make a prepared statement in laravel4 for raw queries?
By default Laravel binds its data using ? and you are binding your data with :foo, meaning there is a mixture of the two approaches and PDO is getting sad about it.
PDO: Invalid parameter number: mixed named and positional parameters
Something like this should get you going in the right direction:
foreach ($queries as $query) {
// Add the update time without merging stuff
$query['update_time'] = date('Y-m-d H:i:s');
// How many bits of data do we have
$bindingCount = count($query);
// Same as before, just get the keys
$keyString = implode(", ", array_keys($query));
// Start off a bindings array with just the values
$bindings = array_values($query);
$updates = [];
foreach ($query as $field => $value){
$updates[] = "{$field} = ?";
$bindings[] = $value;
}
$valueString = implode(',', array_fill(0, $bindingCount, '?'));
$updateString = implode(',', $updates);
DB::statement("INSERT INTO products ({$keyString}) VALUES ({$valueString}) ON DUPLICATE KEY UPDATE {$updateString}", $bindings);
}

Kohana - Insert record with ignore duplicate

How to implement "insert ignore"? using kohana orm While adding multiple records, if few of them may already exist in database using below code adding of all 100 records will be declined.
$query = DB::insert('tablename', array('column1', 'column2','column3'));
foreach ($data as $d) {
$query->values($d);
}
try {
$result = $query->execute();
} catch ( Database_Exception $e ) {
echo $e->getMessage();
}
UPDATE:
Here is how i did This, i have to insert multiple records,
$Xtransactions = "INSERT IGNORE INTO `tablename` (`tid`, `tdate`, `appid`,
`userid`, `user_ip`) VALUES";
foreach ($objSas->trecord as $trow) {
$Xtransactions .= "(".$trow->tid.",'".
date('Y-m-d H:i:s', strtotime($trow->tdate))."',".
$trow->userid.",".
$trow->Xnumber.",'".
$trow->ip."'),";
}
$Xtransactions = substr($Xtransactions , 0, -1);
try {
DB::query(Database::INSERT, $Xtransactions )->execute();
} catch ( Database_Exception $e ) {
echo $e->getMessage();
}
With query builder this is impossible, try to write a raw query.
DB::query(Database::INSERT, 'INSERT IGNORE INTO table VALUES (...)')->execute();
I usually collect such modifications in static helper class, for example
<?php defined('SYSPATH') or die('No direct script access.');
class Helper_DB_Query{
/**
* #param Database_Query_Builder_Insert $insert query thant need to be converted
* #return Database_Query converted query
*/
public static function insert_to_insert_ignore( Database_Query_Builder_Insert $insert ){
$insert = (string) $insert;
$query = preg_replace("/^INSERT(.*)$/", "INSERT IGNORE $1", $insert);
return DB::query(Database::INSERT, $query);
}
}

mysql_num_rows() expects parameter 1 to be resource, boolean in joomla component

When I execute the function below query execute successfully but I get a warning above the result the query:
mysql_num_rows() expects parameter 1 to be resource, boolean
How do I fix this?
public function retrieve()
{
$id=JRequest::getVar('id');
$db =JFactory::getDBO();
$sql="select *
from
#__npco_car,#__npco_namayeshgah,#__npco_agahi
where
#__npco_car.car_id='$id' and
#__npco_namayeshgah.id_namayeshgah=#__npco_agahi.id_namayeshgah and
#__npco_car.car_id=#__npco_agahi.car_id
";
$db->setQuery($sql);
$db->query();
$row = $db->getNumRows();
if($row == 1) {
return $db->loadAssocList();
} else {
$db = JFactory::getDBO();
$sql="select *
from
#__npco_car,#__npco_useragahi,#__npco_user
where
#__npco_car.car_id='$id' and
#__npco_user.id_user=#__npco_useragahi.id_user and
#__npco_car.car_id=#__npco_useragahi.car_id
";
$db->setQuery($sql);
return $db->loadAssocList();
}
}
Your code has several issues.
Never use unchecked/unvalidated request values, not even in examples!
Use the query builder.
Reduce coupling by a) setting the database in the constructor, which is done already in models, and b) retrieve the id in the controller.
You try to get all fields (*) from multiple tables, which have some column names in common. That will not work.
Have a look at JOINs.
This will work:
public function retrieve($id)
{
$query = $this->_db->getQuery(true);
$query->select('#__npco_car.*')->from(array('#__npco_car', '#__npco_namayeshgah', '#__npco_agahi'));
$query->where('#__npco_car.car_id = ' . (int) $id);
$query->where('#__npco_namayeshgah.id_namayeshgah = #__npco_agahi.id_namayeshgah');
$query->where('#__npco_car.car_id = #__npco_agahi.car_id');
$this->_db->setQuery($sql);
$rows = $this->_db->loadAssocList();
if (empty($rows))
{
$query = $this->_db->getQuery(true);
$query->select('#__npco_car.*')->from(array('#__npco_car, #__npco_useragahi, #__npco_user'));
$query->where('#__npco_car.car_id = ' . (int) $id);
$query->where('#__npco_user.id_user = #__npco_useragahi.id_user');
$query->where('#__npco_car.car_id = #__npco_useragahi.car_id');
$db->setQuery($sql);
$this->_db->setQuery($sql);
$rows = $this->_db->loadAssocList();
}
return $rows;
}
may be this is your issue..
Change your query as following
$sql="select *
from
#__npco_car,#__npco_namayeshgah,#__npco_agahi
where
#__npco_car.car_id='".$id."' and
#__npco_namayeshgah.id_namayeshgah=#__npco_agahi.id_namayeshgah and
#__npco_car.car_id=#__npco_agahi.car_id
";
$sql="select *
from
#__npco_car,#__npco_useragahi,#__npco_user
where
#__npco_car.car_id='".$id."' and
#__npco_user.id_user=#__npco_useragahi.id_user and
#__npco_car.car_id=#__npco_useragahi.car_id
";

How can I SELECT from multiple tables in CodeIgniter

I have three tables: (to keep it simple I'll only show the relevant fields)
Articles (id, title, text, author)
Comments (id, article_id, text, author)
Users (user_id, user_type, first_name, last_name, email, password)
In the articles table, because an author can have multiple articles, I only store the author's user_id from the users table, and I do the same for the comments table.
My problem is when I run an ActiveRecord query in the articles_model to get all articles along with that articles associated comments, and then echo the author in my view with $row->author, I only get the author's user_id which is 1, 2, 3, etc etc.
How do I go into the users table (different table) in that same query and get the authors actual first_name and last_name and return that?
Here's my code:
Controller:
$data['articles'] = $this->getArticles();
$this->load->view('articles_view', $data);
function getArticles() {
$this->load->model('articles_model');
$articles = $this->articles_model->getAllArticles();
return $articles;
}
articles_model:
function getAllArticles() {
$this->db->where('id', $this->uri->segment(3));
$query = $this->db->get('articles');
return $query;
}
articles_view:
<?php foreach($articles->result() as $row) { ?>
<?php echo $row->author ?>
<?php echo $row->text ?>
<?php } ?>
I have a ton of other fields, but this is an extremely stripped down version for simplicity's sake.
If I echo the above $row->author, I'm only going to get the user_id. I need to get the user's name from the users table instead. Surely I don't have to do another separate function call and pass more information into the view. Any help here would be greatly appreciated and would actually open up a world for me :)
Try this (or just have an idea):
I assumed that user_id from your users table is foreign key of articles and comments table since you said that the authors and commentators user_id are stored in users table.
On your controller:
$data['articles'] = $this->getArticles();
$this->load->view('articles_view', $data);
function getArticles() {
$this->load->model('articles_model');
$articles = $this->articles_model->getArticlesById();
return $articles;
}
On your model:
// this will get the article of a certain author
function getArticlesById()
{
$this->db->where('id', $this->uri->segment(3));
$q = $this->db->get('articles');
if($q->num_rows() > 0)
{
$q = $q->row_array();
$result = $this->getCommentsAndAuthors($row);
return $result;
}
return 0;
}
// this will get the comments of each articles of the author and the author of the comments
function getCommentsAndAuthors($row)
{
$result = $data = array();
$this->db->select('c.*, u.firstname, u.lastname');
$this->db->from('users u');
$this->db->where('u.id', $row['user_id']);
$this->db->join('comments c', 'c.id = u.id');
$q = $this->db->get();
foreach($q->result_array() as $col)
{
$data[] = $col;
}
$result['article'] = $row;
$result['comments'] = $data;
return $result;
}
I'm not sure if its work but that's the idea.
I have found a solution that works well for me which I will post and try to explain.
My Controller is like this:
function fullArticle()
{
$data['article'] = $this->getArticleDetail();
$data['comments'] = $this->getNewsTrendsComments();
$this->load->view('inner_view', $data);
}
function getArticleDetail()
{
$this->load->model('articles_model');
$articles = $this->articles_model->getArticles();
return $articles;
}
function getComments()
{
$this->load->model('articles_model');
$comments = $this->articles_model->getComments();
return $comments;
}
articles_model:
function getArticles()
{
$this->db->where('id', $this->uri->segment(3));
$query = $this->db->get('articles');
return $query;
}
function getComments()
{
$this->db->select('*');
$this->db->from('comments w');
$this->db->where('article_id', $this->uri->segment(3));
$this->db->join('users wc','w.author = wc.user_id');
$data = $this->db->get();
return $data;
}
As you can see, the getComments function in my model was the key. It's the JOIN statement that handles what I was trying to accomplish. I know there are probably cleaner and more efficient ways to do this, by combining the two functions, but as a beginner I wanted to keep it easier to understand.
Hopefully this can help others.