PDOStatement::bindParam() not setting AI value from MySQL insert? - php

I have a simple insert statement using PDO php class.
the 'id' column is identity (doy) with autoincrement.
$statement = $db->prepare('INSERT INTO demographics (id,location_id,male,ethnicity_id,birthyear) VALUES (:id,:location_id,:male,:ethnicity_id,:birthyear)');
$statement->bindParam(':id',$demo->id,PDO::PARAM_INT,4);
$statement->bindParam(':location_id', $demo->locationid,PDO::PARAM_INT);
$statement->bindParam(':male',$demo->male,PDO::PARAM_BOOL);
$statement->bindParam(':ethnicity_id',$demo->ethnicityid,PDO::PARAM_INT);
$statement->bindParam(':birthyear',$demo->birthyear,PDO::PARAM_INT);
$statement->execute();
print_r($demo);
Even though the statement executes correctly (row is correctly written), $demo->id is null.
I have a very similar statement for a different table, and it correctly returns the id column.
Any thoughts?

If id is autoincremented, you don't need to specify it when inserting into the table. What value are you giving to $demo->id?
If you need the id of the inserted entry, you could retrieve it using PDO::lastInsertId, then set the object's $id field with the value.

Related

how to insert data from primary key column to foregin key

i am inserting data from a form i want when i will insert data so the first column primary id which is using in second column as a foreign key should be increased
i have tried this code but not working
first table code
$this->db->query("insert into af_ads (ad_title,ad_pic,ad_description)
values ('$title','$filepath','$description')");
second table code
$this->db->query("insert into af_category (cat_type,ad_id_fk)
values ('$category','ad_id')");
NOTE: i want to insert ad_id into ad_id_fk
Try this:
// Your first query
$this->db->query("insert into af_ads(ad_id, ad_title, ad_pic, ad_description)
values ('', '$title', '$filepath', '$description')");
$ad_id = $this->db->insert_id(); // This returns the id that is automatically assigned to that record
// Use the id as foreign key in your second insert query
$this->db->query("insert into af_category (cat_type,ad_id_fk)
values ('$category', $ad_id)");
MySQL provides the LAST_INSERT_ID function as way to retrieve the value generated for an AUTO_INCREMENT column from the immediately preceding INSERT statement.
A lot of client libraries make this conveniently avaiable (e.g. PDO lastInsertId function.)
(I'm not familiar with CodeIgniter or ActiveRecord, so I can't speak to how that's made available.
Your code looks like it's using the PDO interface... but I'm not sure about that.
# either we need to check return from functions for errors
# or we can have PDO do the checks and throw an exception
$this->db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
# attempt insert which will generate AUTO_INCREMENT value
$this->db->query("INSERT (ad_id, ... ) VALUES (NULL, ...)");
# if previous insert successfully inserted a row (or rows)
$ad_id = $this->db->lastInsertId();
You really need to check whether the previous insert was successful or not. If you aren't going to code that check yourself, then PDO does provide a mechanism that performs this checking automatically, and will throw an exception if a MySQL error occurs.
I've avoided copying your original code, which looks like it's vulnerable to SQL Injection. If you're using PDO, you can make effective use of prepared statements with bind placeholders, rather than including values in the SQL text.

PDO: Is lastInsertId() a separate query?

If I have this code:
<?php
$q = $sql->prepare("INSERT INTO `table` (row) VALUES ('1')");
$q->execute();
$lastid = $sql->lastInsertId(); // is this a 2nd query?
?>
Would it run as two separate SQL queries?
If so, is there a way to do it in one?
$lastid = $sql->lastInsertId();
it works like a query because it will select from database the last inserted id.
as the documentation said
Returns the ID of the last inserted row, or the last value from a sequence object, depending on the underlying driver.
No, in fact it doesn't run an SQL query.
Here's the line from ext/pdo_msyql/mysql_driver.c:
char *id = php_pdo_int64_to_str(mysql_insert_id(H->server) TSRMLS_CC);
This is a call to the MySQL API, mysql_insert_id(). This internally accesses the last insert id as a property, not by running SQL.

How do I bind current column value in PDO?

I have a feature in my web app where a table is "quick-editable", that is, its cells can be edited directly. When the user saves his changes, the client sends to the server the changed rows, with their changed columns (excluding non-changed columns, just to clarify), and their corresponding IDs.
In order to do UPDATE queries efficiently, I am using PDO's prepared statement feature. Here is an equivalent statement what I currently came up:
UPDATE table
SET
col1 = :arg_col1,
col2 = :arg_col2,
col3 = :arg_col3
WHERE
ID = :arg_ID
Then I came up with this problem in which I cannot set a column into its current value. Because only the edited column(s) in a row is/are submitted, I only need to bind the data to their respective column(s). For example, if only col1 and col2 are changed, the resulting statement should be
UPDATE table
SET
col1 = 'new data',
col2 = 'an edit',
col3 = col3 /* Use the current value of the column */
WHERE
ID = 153454
Modifying the statement directly would definitely nullify the performance improvement of using the same prepared statement for updating multiple rows. Sadly, PDO doesn't seem to have an option to bind a column to its current value.
How should I solve this problem?
ADDITIONAL: I do not wish to send all the columns, for performance reasons.
Unfortunately, an approach you are aiming to, won't actually work. You just can't prepare a statement in one call and then use it in all subsequent calls - you'll have to prepare it every time again.
So, there is no point in creating a generic query. Thus, you can create a custom query for the very data set. And this latter task can be automated: just create your UPDATE statement dynamically.
A solution, based on the tag wiki (scroll to the very bottom):
// first, have your update data in array (you can omit this line though)
$update = $_POST;
// next, list all fields a user allowed to
$allowed = array("col1","col2","col3");
// finally, create a SET statement query dynamically
$set = pdoSet($fields,$values, $update);
// voila - your query contains only fields were POSTed:
$sql = "UPDATE users SET $set WHERE id = :id";
$stm = $dbh->prepare($sql);
// just add an ID and execute
$values["id"] = $_POST['id'];
$stm->execute($values);
You actually don't want the col3 in the sql, what you need to do is to build the sql dynamically, only add the changed columns to the sql.

PDO + PHP lastInsertId() issue

Wouldn't there be a problem with it if for example when a user clicks on a link, a new row is automatically inserted and then the php code requests the last inserted id, and at the same time another row is inserted by another user, so the returned id is actually not the one I'm expecting..?
Am I wrong? Is there a way to do the same without that 'security' hole?
(like maybe from within the prepared statement or something...)
P.S the id is automatically generated.
Thank you.
As mentioned in the manual:
LAST_INSERT_ID() (with no argument) returns a BIGINT (64-bit) value representing the first automatically generated value that was set for an AUTO_INCREMENT column by the most recently executed INSERT statement to affect such a column. For example, after inserting a row that generates an AUTO_INCREMENT value, you can get the value like this:
mysql>SELECT LAST_INSERT_ID();
->195
The currently executing statement does not affect the value of
LAST_INSERT_ID(). Suppose that you generate an AUTO_INCREMENT value
with one statement, and then refer to LAST_INSERT_ID() in a
multiple-row INSERT statement that inserts rows into a table with its
own AUTO_INCREMENT column. The value of LAST_INSERT_ID() will remain
stable in the second statement; its value for the second and later
rows is not affected by the earlier row insertions. (However, if you
mix references to LAST_INSERT_ID() and LAST_INSERT_ID(expr), the
effect is undefined.)
If the previous statement returned an error, the value of
LAST_INSERT_ID() is undefined. For transactional tables, if the
statement is rolled back due to an error, the value of
LAST_INSERT_ID() is left undefined. For manual ROLLBACK, the value of
LAST_INSERT_ID() is not restored to that before the transaction; it
remains as it was at the point of the ROLLBACK.
So, LAST_INSERT_ID() is always transaction-safe (even though you don't use transaction).
The MySQL Server transfers the insert ID as part of the OK message after a successful INSERT. This ID is stored in PDO, therefore without a round-trip to the server PDO can return you the correct ID for your connection in a safe way.
Reference: http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#OK_Packet
To counteract this you would use a transaction.
This would essentially isolate your insert from others, so as long as your Insert/lastInsertId() call is within the same transaction, it will work just fine.

Get autoincrement id after an insert query performed with a prepared statement

If I execute an insert query with a stored procedure with php and the mysqli_* functions, is there a way to retrieve the value of an autoincrement id field?
mysqli->insert_id does not seem to work.
Are you sure the last query you preformed was an INSERT?
mysqli->insert_id seems the proper answer:
Return Values
The value of the AUTO_INCREMENT field that was updated
by the previous query. Returns zero if
there was no previous query on the
connection or if the query did not
update an AUTO_INCREMENT value.
You could try to make a query to MySql like so:
SELECT LAST_INSERT_ID()
Not sure if it works with stored procedures though.
You could add this statement in your stored procedure after the insert:
SET #saved_id = LAST_INSERT_ID()
Then, execute this query after calling the procedure:
SELECT #saved_id
mysqli->insert_id (where mysqli represents your database connection)
must be used directly after the insert. If you run other queries on the same connection
before attempting to read insert_id you get 0 returned.

Categories