MySQLi does not return error code - php

In my MySQL database I have a table "table1" with unique constraint set on column "name" - I want to prevent duplicate names.
If there's already name 'John' in table this code:
$db=new mysqli(...);
$sql="INSERT INTO table1 SET id=10,name='John'";
if(!$db->query($sql))
{
if($db->errno==1062)
{
throw new InsertNonUniqueException(...);
}
else
{
throw new InsertException(...);
}
}
should throw InsertNonUniqueException() (my own exception). Instead, it throws InsertException().
Execution of query returns false and execution enters the if() loop. Also $db->row_affected is -1 but problem is that $db->errno is always O (it should be 1062)!!! So I can't detect that my insert error was caused by violating unique key constraint on name column!
I don't know why mysqli does not return 1062 code when unique key constraint violation occurs!

I can't leave a comment, thus going to ask you here.
Please provide the result of SHOW CREATE TABLE table1;
I can't reproduce your problem using your code and next table:
CREATE TABLE `table1` (
`name` varchar(11) COLLATE utf8_unicode_ci NOT NULL,
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Am I the only one around here that thinks you have an error in your SQL syntax?.. There is no room for SET in INSERT INTO, because you can only use SET in UPDATE statements (assuming you habe MySQL in version 5.5 or below).
INSERT INTO syntax is like the following (as described in the docs):
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
OR
INSERT INTO tbl_temp2 (fld_id)
SELECT tbl_temp1.fld_order_id
FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;
Try it like this:
<?php
$sql="INSERT INTO table1 (id, name) VALUES ('10', 'John')";
...

step 1
make sure that the table has a unique key
SHOW CREATE TABLE table1
expected result
CREATE TABLE `table1` (
`id` INT(11) default NULL,
`name` varchar(11) COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci
if there is UNIQUE KEY name (name) we have a unique key
step 2
try to change your code
$db = new mysqli(...);
// first insert
if( !$db->query("INSERT INTO table1 (id, name) VALUES (10, 'John')") ) {
throw new Exception($db->error);
}
// second insert (for me raise: Duplicate entry 'John' for key 'name')
if( !$db->query("INSERT INTO table1 (id, name) VALUES (11, 'John')") ) {
throw new Exception($db->error);
}
Please, try these two steps
Side note: if you have name and id as duplicates, only the first duplicate encountered will be returned in the message.

The only issue i have with your code is that:
having setup your table and columns.
I setup a unique index on the table. I did .. stuff on a two column table that ensure it works.
You missed the 'new'
keyword when you 'throw exceptions'.
this is the only error with your posted code that i could find.
i.e: throw new Exception('Division by zero.'); // example taken from PHP manual.

Related

INSERT if not exists UPDATE if exists does not work

I am trying to have the solution of the very well known INSERT IF NOT EXISTS UPDATE IF EXISTS.
But mine is not working. I don't know why, Can anyone figure it out?
Here is what I have tried yet:
$qprep = ("INSERT INTO gpsdata (`imei`,`latitude`,`longitude`)
VALUES ('$imei','$lathex1','$lonhex1') ON DUPLICATE KEY UPDATE
latitude='$lathex1',longitude='$lonhex1';");
I want to update the row if the same "imei" is in there, or Insert if its not.
I have my ROW as the primary key and from phpmyadmin, I have made the imei "unique".
What am I doing wrong?
My SQL DUMP:
CREATE TABLE IF NOT EXISTS `gpsdata` (
`ROW` int(11) NOT NULL AUTO_INCREMENT,
`IMEI` varchar(255) NOT NULL,
`Latitude` varchar(255) NOT NULL,
`Longitude` varchar(255) NOT NULL,
PRIMARY KEY (`ROW`),
UNIQUE KEY `IMEI` (`IMEI`,`Latitude`,`Longitude`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=36 ;
--
-- Dumping data for table `gpsdata`
--
INSERT INTO `gpsdata` (`ROW`, `IMEI`, `Latitude`, `Longitude`) VALUES
(24, '#2:359672050035420:2:*', '90.370803333333', '0'),
(30, '#2:359672050035420:2:*', '90.370803333333', '23.7584'),
(27, '#2:359672050035420:2:*', '90.370803333333', '23.75854'),
(35, '1:135790246811221:1:*', '1.0961283333333', '1.759595'),
(32, '1:135790246811221:1:*', '1.759595', '1.0961283333333');
As seen here, you need to replace the actual values in the update statement with either A| references to the alreay existing values (e.g. longitude=longitude) or B| references to the new values (e.g. longitude=VALUES(longitude), but not longitude='$lonhex1').
Your query should be rewritten:
$qprep = ("INSERT INTO gpsdata (`imei`,`latitude`,`longitude`)
VALUES ('$imei','$lathex1','$lonhex1') ON DUPLICATE KEY UPDATE
latitude=VALUES(latitude),longitude=VALUES(longitude)");
If you have statement based replication running on this server then there would be a problem, see the warning below:
Unsafe statement written TO the BINARY LOG USING statement FORMAT
since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE
ON a TABLE WITH more THAN ONE UNIQUE KEY IS unsafe
You have to pass the column name and its value on which you have used the primary key or unique key on which you want the Duplicate Key Update.
If it gets the id(in your case ROW, latitude and longitude column on which primary and unique key is defined ) in the database, it updates it, else it inserts a new row.
$qprep = ("INSERT INTO gpsdata (`imei`,`latitude`,`longitude`)
VALUES ('$imei','$lathex1','$lonhex1') ON DUPLICATE KEY UPDATE
latitude=VALUES(latitude),longitude=VALUES(longitude)");
Example:
INSERT INTO gpsdata (`row`,`imei`,`latitude`,`longitude`)
VALUES ('24','1','TEST','TEST') ON DUPLICATE KEY UPDATE
`IMEI`='2', `Latitude`='2',`Longitude`='2';
or
INSERT INTO gpsdata (`imei`,`latitude`,`longitude`)
VALUES ('1','TEST','TEST') ON DUPLICATE KEY UPDATE
`IMEI`='2', `Latitude`=VALUES(`Latitude`),`Longitude`=VALUES(`Longitude);

Using INSERT WHERE with variables

I am trying to make an SQL query that :
IF the $post_id exists then it updates the records,
IF NOT then then it creates the record
Here is my code
$vote_new_total = $vote_total + $vote;
$vote_count = $vote_count + 1;
$query = " INSERT INTO cute_review_vote (vote_total, vote_count)
VALUES ('$vote_new_total', '$vote_count')
ON DUPLICATE KEY UPDATE vote_total = $vote_new_total, vote_count = $vote_count
WHERE post_id = $post_id";
mysql_query($query) or trigger_error(mysql_error()." in ".$sql);
However, I keep getting the following error:
Notice: 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 'WHERE post_id = 214748364' at line 4 in in C:\xampp\htdocs\xbm-vote\do_vote.php on line 68
Is this an issue with my syntax or am I missing something more obvious than that?
Any help/advice would be greatly appreciated. Thanks.
There is no where with ON DUPLICATE statement. Always check syntax: http://dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html
Also, that is not a secure query. Turn that into a prepared statement.
http://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php
EDIT: Updating answer since OP didn't understand usage of ON DUPLICATE statement:
ON DUPLICATE will consider that you're trying to insert a KEY value.
Consider the example table:
CREATE TABLE `user` (
`email` varchar(50) NOT NULL,
`name` varchar(20) NOT NULL,
`is_active` tinyint(4) NOT NULL,
`datecreated` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`email`)
);
And the query:
INSERT INTO user (email, name, is_active) VALUES ("user#user.com", "User", 1)
ON DUPLICATE KEY UPDATE name = "User Edited", is_active = 0
Since we're setting PRIMARY KEY as email, and the insert statement is inserting a key, then, at the second time you run the query, ON DUPLICATE would run once a email is already on the table, because it is the KEY and you are trying to insert it again, but you defined a ON DUPLICATE KEY ....
If a table runs with a AUTO_INCREMENT column, is most likely you have to SELECT post_id applying some filter with WHERE statement.
Ok, I found my problem.
INSERT INTO cute_review_vote (post_id, vote_total, vote_count)
VALUES ('$post_id', '$vote_new_total', '$vote_count')
ON DUPLICATE KEY UPDATE vote_total = $vote_new_total, vote_count = $vote_count
I realized, thanks to Fabiano, that the WHERE clause is not required.
WHERE post_id = $post_id"
Is simply replaced by defining the database entry within the INSERT INTO command.

update then replace dies

If there is a row for user_id then I want to update, if not insert (but I was told to use replace). In the table there is id (which is primary key, auto inc) and user_id (index, session relates to). I have a form that when the data is changed it should be changed in the database for that particular user in session, otherwise it is just added for that particular user in session
if (empty($err)) {
$thesis_Name = mysql_real_escape_string($_POST['thesis_Name']);
$abstract = mysql_real_escape_string($_POST['abstract']);
$query="UPDATE thesis SET thesis_Name ='$thesis_Name',
abstract='$abstract' WHERE id='$_SESSION[user_id]'
IF ROW_COUNT()=0
REPLACE INTO thesis (thesis_Name,abstract)VALUES ('$thesis_Name', '$abstract')
";
mysql_query($query) or die();
// query is ok?
if (mysql_query($the_query, $link) ){
// redirect to user profile
header('Location: myaccount.php?id=' . $user_id);
}
With this the page just dies.
EDIT:
`thesis` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`thesis_Name` varchar(200) NOT NULL,
`abstract` varchar(200) NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`)
)
Thanks so much
You don't need to do the UPDATE first - REPLACE handles all of this for you. From the MySQL manual:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted. See Section 13.2.5, “INSERT Syntax”.
Therefore, so long as id is a unique key in your thesis table, the only SQL you need is:
REPLACE INTO thesis (id, thesis_Name, abstract)
VALUES ('$_SESSION[userid]', '$thesis_name', '$abstract');
There are a few things in your code that pose problem. First you don't have to do an insert and a replace in the same query : replace will insert if there is no row to replace (besides, I'm not even sure the sql syntax you're using is correct)...
Then you do a mysql_query($query) or die() which is probably where your code dies (maybe due to the fact that the sql syntax you used could be incorrect).
Right after that, you do a mysql_query again, which would reexecute the query a second time. Anyway, if your query didn't work, your code would have died on the previous line...
What you could do would be
$query = "REPLACE INTO blablabla";
if (!mysql_query($query))
echo "the query failed";
else header ("location:blabla");
but your query should mention for which user_id you want to update like this
REPLACE INTO thesis (id, thesis_Name, abstract)
VALUES ('{$_SESSION[userid]}', '$thesis_name', '$abstract');
INSERT
INTO thesis (id, abstract, thesis)
VALUES ('$_SESSION[user_id]', '$abstract', '$thesis_Name')
ON DUPLICATE KEY
UPDATE
abstract = VALUES(abstract),
thesis_Name = VALUES(thesis_Name)
You can do it with prepared statements.You can see an example sql ;
DROP PROCEDURE IF EXISTS `UPDATETHESIS`
|
CREATE PROCEDURE `UPDATETHESIS` (IN _id VARCHAR(50), IN _thesis_name VARCHAR(50), IN _abstract VARCHAR(50))
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY INVOKER
IF EXISTS (SELECT * FROM thesis WHERE id = _id)
BEGIN
UPDATE thesis SET thesis_Name = _thesis_name,
abstract = _abstract WHERE id = _id
END
ELSE
BEGIN
INSERT INTO thesis (thesis_Name,abstract) VALUES (_thesis_name, _abstract)
END
You can call this like CALL UPDATETHESIS(userid, thesis_name, abstratc);

query takes 70 ms to execute

I have an MySQL table named i_visited structured like: userid,tid,dateline
And I run this condition in view_thread.php page:
if (db('count','SELECT userid FROM i_visited
WHERE tid = '.intval($_GET['id']).'
AND userid = '.$user['id']))
mysql_query('UPDATE i_visited
SET dateline = unix_timestamp(now())
WHERE userid = '.$user['id'].'
AND tid = '.intval($_GET['id']));
else
mysql_query('INSERT INTO i_visited (userid,tid,dateline) VALUES
('.$user['id'].','.intval($_GET['id']).',unix_timestamp(now()))');
The problem is that it executes in 80/100 ms (on Windows) 40/60 (on Linux)
1 row affected. (query executed in 0.0707 sec)
The mysql_num_rows() aka db('count',sql) uses 2 / 3 ms, so the problem is at the update and the insert.
P.S. i_visited is an utf8_unicode_ci (InnoDB), has anyone seen this problem?
Other queries run normal (2 / 3 milliseconds)
CREATE TABLE i_visited (
userid int(10) NOT NULL,
tid int(10) unsigned NOT NULL,
dateline int(10) NOT NULL,
KEY userid (userid,tid),
KEY userid_2 (userid),
KEY tid (tid) )
ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
You do not need to do a select to check existence and then choose either Update or Insert.
You can use MySQL's ON DUPLICATE KEY UPDATE Feature like this.
$query = 'INSERT INTO
i_visited (userid,tid,dateline)
VALUES (' .
$user['id'] . ',' .
intval($_GET['id']) . ',
unix_timestamp(now()))
ON DUPLICATE KEY UPDATE
dateline = unix_timestamp(now())';
mysql_query($query);
This query will insert a new row if there is now KEY conflict, and in case a duplicate key is being inserted, it will instead execute the update part.
And as you have a KEY userid (userid,tid) in your CREATE Statement the above query is equivalent to your if...else block.
Try this and see if there are any gains
You can also use REPLACE INTO, as there are only the specified 3 columns, like this
$query = 'REPLACE INTO
i_visited (userid,tid,dateline)
VALUES (' .
$user['id'] . ',' .
intval($_GET['id']) . ',
unix_timestamp(now()))';
mysql_query($query);
But I would suggest looking at ON DUPLICATE KEY UPDATE as it is more flexible, as it can be used on a table with any number of columns, whereas REPLACE INTO would only work in some limited cases as other column values would also need to be filled in the REPLACE INTO statement unnecessarily
I think (part) of the problem is that your table does not have an explicit primary key.
You've only declared secondary keys.
Change the definition to:
CREATE TABLE i_visited (
userid int(10) NOT NULL,
tid int(10) unsigned NOT NULL,
dateline int(10) NOT NULL,
PRIMARY KEY userid (userid,tid), <<----------
KEY userid_2 (userid),
KEY tid (tid) )
ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
InnoDB does not work well without an explicit primary key defined.

PHP: use id to another column

Ok, so i have a normal query that inserts to the database.
mysql_query("INSERT INTO users_pm_in (uID, msg) VALUES ('$uID', '$msg')");
Now this table has also a column called "id" with auto_increment & primary key.
When it inserts it auto makes number for the column in the row. Now I want this number, and put it in column dialog, in the same row. So the inserted row have the same number/id in "id" and "dialog". How can i do that?
Not sure if this can be done in one query (or why you even want to do this), but you can use this:
mysql_query("INSERT INTO users_pm_in (uID, msg) VALUES ('$uID', '$msg')");
mysql_query("UPDATE users_pm_in SET dialog = id WHERE id = '".mysql_insert_id()."');
Be sure to escape the variables properly also.
I think it would be easier to remove the autoincrement and add the id+dialog value yourself.
Check out mysql_insert_id()
You can do this, altough it's not very efficient...
Supose you have this table:
CREATE TABLE `test` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`a` INT(10) NULL DEFAULT '0',
`b` INT(10) NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
ENGINE=MyISAM
ROW_FORMAT=DEFAULT
You can perform the following query:
INSERT INTO test (a, b) SElECT IFNULL((MAX(id) +1),1), 200 FROM test;
Notice that "200" is some random value that will be inserted on "b" column.

Categories