Skip to content

Better PDO::inTransaction #4996

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
Closed

Conversation

twose
Copy link
Member

@twose twose commented Dec 10, 2019

It looks good for me...
Is there any historical reason to prevents us from doing this?

and we can't do such things now (although it may not make sense):

$db = new PDO(
    'mysql:host=127.0.0.1;dbname=test;charset=utf8',
    'root', 'root'
);
$db->exec('BEGIN');
$db->rollBack();
PHP Fatal error:  Uncaught PDOException: There is no active transaction in ...

@cmb69
Copy link
Member

cmb69 commented Dec 10, 2019

Would that also work with libmysqlclient?

@twose
Copy link
Member Author

twose commented Dec 10, 2019

is libmysql also available in PHP7?
I just read the source code of mysqlnd and it updates the server data after each operation, but I do not know anything about libmysql

@cmb69
Copy link
Member

cmb69 commented Dec 10, 2019

ext/mysqli and ext/pdo_mysql can still be built either against mysqlnd or libmysql (see https://externals.io/message/106086, though). Until we decide to drop support for libmysql, we have to support it (at least in a minimal way, e.g. PDO::inTransaction() might always fail there).

@twose
Copy link
Member Author

twose commented Dec 10, 2019

I can only say that I support dropping support for building against libmysql :)

default:
assert(0);
}
var_dump($db->inTransaction());
Copy link
Contributor

Choose a reason for hiding this comment

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

does consequent calls hit the server again and again?

Copy link
Member Author

Choose a reason for hiding this comment

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

does consequent calls hit the server again and again?

Do you mean that whether this call requires network IO? The MySQL server will tell the client if it is in a transaction in every response by a flag, so we can get the latest status no matter what command is executed

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you mean that whether this call requires network IO?

yes

The MySQL server will tell the client if it is in a transaction in every response by a flag, so we can get the latest status no matter what command is executed

so does this query this local flag or did it require network IO every time?

Copy link
Member Author

@twose twose Jul 10, 2020

Choose a reason for hiding this comment

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

not required, before sending a new request, the state of the transaction will not change, so the state we got from the last response is reliable

Copy link
Contributor

Choose a reason for hiding this comment

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

@twose Thanks, I already hit this several times, your PR looks very good, 👍

@mvorisek
Copy link
Contributor

mvorisek commented Jul 10, 2020

For me, it seems almost like a bug fix, @cmb69, can we merge this?

@cmb69
Copy link
Member

cmb69 commented Jul 10, 2020

@johannes, @andreyhristov, any objections to merge this PR?

@johannes
Copy link
Member

I haven't gone through this in depth, but I wonder about the practical value. You will know that you are in some transaction, but not exactly which. There could have been an implicit commit (i.e. due to a ALTER TABLE) after the previous operation. Thus you have to be aware about what you are doing.

I wonder if this has to be a fatal error though ... that seems weird to me. I will try to think a bit about this.

@johannes
Copy link
Member

Ah, one thing I didn't realized on my first look: This is a common PDO method, so yeah, adding this seems fine. Still I think we should think about lowering away from fatal error ...

@twose
Copy link
Member Author

twose commented Jul 22, 2020

So, can anyone approve it? or any more suggestions?

@php-pulls php-pulls closed this in 6a4eeb1 Sep 23, 2020
@nikic
Copy link
Member

nikic commented Sep 23, 2020

I've done the necessary changes to support libmysqlclient and committed this patch.

@nikic
Copy link
Member

nikic commented Oct 20, 2020

I opened #6355 as a followup fix for https://bugs.php.net/bug.php?id=80260.

php-pulls pushed a commit that referenced this pull request Oct 26, 2020
This addresses an issue introduced by #4996 and reported in
https://bugs.php.net/bug.php?id=80260.

Now that PDO::inTransaction() reports the real transaction state
of the connection, there may be a mismatch with PDOs internal
transaction state (in_tcx). This is compounded by the fact that
MySQL performs implicit commits for DDL queries.

This patch fixes the issue by making beginTransaction/commit/rollBack
work on the real transaction state provided by the driver as well
(or falling back to in_tcx if the driver does not support it).

This does mean that writing something like

    $pdo->beginTransaction();
    $pdo->exec('CREATE DATABASE ...');
    $pdo->rollBack(); // <- illegal

will now result in an error, because the CREATE DATABASE already
committed the transaction. I believe this behavior is both correct
and desired -- otherwise, there is no indication that the code did
not behave correctly and the rollBack() was effectively ignored.
However, this is also a BC break.

Closes GH-6355.
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.

5 participants