Skip to content

🐛 Fixed Bug #80908 PDO::lastInsertId() return wrong. #6810

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

AtlanticF
Copy link

Fixed Bug #80908

MySQL api function last_insert_id() always return unsigned interger,
but in ext.pdo_mysql we use int64 to receive the uint64 return value.
When MySQL table auto_increment id bigger than the maximum value of
int64, ext.pdo_mysql will treat as int64.

Copy link
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure the approach of mimicking the signed version is totally correct, as I could imagine some overflow into negative numbers for very large 64 bit integers, can you add a test?

Comment on lines +293 to +295
if (i64 == 0) {
return ZSTR_CHAR('0');
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also handle all numbers which are a single digit

{
char buffer[65];
char outbuf[65] = "";
register char *p;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
register char *p;
char *p;

From my understanding this is pretty meaningless.

p = &buffer[sizeof(buffer)-1];
*p = '\0';

while ((uint64_t)i64 > (uint64_t)ZEND_LONG_MAX) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
while ((uint64_t)i64 > (uint64_t)ZEND_LONG_MAX) {
while (i64 > (uint64_t)ZEND_LONG_MAX) {

i64 is already an uint64_t

@AtlanticF
Copy link
Author

AtlanticF commented Mar 29, 2021

I'm not sure the approach of mimicking the signed version is totally correct, as I could imagine some overflow into negative numbers for very large 64 bit integers, can you add a test?

@Girgias Thanks for your code review. I will provider a test. The test steps:

  1. Create a test table
// Let the table auto_increment id start from `10376293541461622799`. It's bigger than int64.
create table foo (`id` bigint(20) unsigned AUTO_INCREMENT, `name` varchar(5), primary key (`id`)) ENGINE = InnoDB AUTO_INCREMENT=10376293541461622799;
  1. Run the test.php
<?php
$dbh = new PDO('mysql:host=docker.for.mac.localhost:33060;dbname=test', 'root', 'secret');
$dbh->exec("insert into foo (`name`) values ('bar')");
echo $dbh->lastInsertId() . PHP_EOL;
// If we not fix the bug, this test will return a string '-8070450532247928817'

In fact, MySQL Client C API function last_insert_id() is always return an unsigned int64

@nikic
Copy link
Member

nikic commented Apr 13, 2021

I don't think PDO should be responsible for implementing this functionality, so I've added some generic Zend APIs in 65a5c18.

This PR should now just be a matter of switching from zend_i64_to_str to zend_u64_to_str.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants