Problem/Motivation
The PostgreSQL driver uses a savepoint named mimic_implicit_commit to recover from a failed query without aborting the surrounding transaction. A SELECT can execute another SELECT during query alteration, before the first query releases its savepoint. Attempting to create the same savepoint again throws TransactionNameNonUniqueException: mimic_implicit_commit is already in use.
This was originally reported with Workbench Moderation and Group when saving content as a user without bypass node access. The failure can also be reproduced without contributed modules, and was reproduced on Drupal 11.4.6 with PostgreSQL 16 and PHP 8.4.22.
Steps to reproduce
- Use the PostgreSQL database driver and start an outer transaction.
- Execute a tagged SELECT query whose query-alter hook executes another SELECT on the same connection.
- The nested SELECT attempts to create the existing
mimic_implicit_commitsavepoint and throws the exception.
The core-only regression test in MR !17015 reproduces this sequence. See #93 for the reproduction and local results.
Proposed resolution
MR !17015 targets main and adapts the savepoint-existence guard from MR !10859 to the current transaction API in the PostgreSQL driver's Select::execute(). Create the savepoint only when it does not already exist, so a nested SELECT does not attempt to create a duplicate.
Add regression coverage for nested SELECTs, repeated nested queries, recovery after a failed query, and rollback of the outer transaction.
Testing
- Without the fix, the new regression test fails in the test-only job, confirmed by oily in #94.
- With the fix, all automatic jobs passed in the PostgreSQL 18 / PHP 8.5 pipeline, reported in #95.
- Local testing on Drupal 11.4.6 / PostgreSQL 16 / PHP 8.4.22: SELECT suite, 44 tests and 111 assertions; PostgreSQL transaction suite, 21 tests and 271 assertions, with 2 existing skips and no failures. Dependency deprecations were reported.
- The moderated-node draft creation and continuation scenario with node grants and an existing node-reference field passes with the patch. The draft continuation scenario previously returned HTTP 500 and now passes 30 functional assertions. No access, validation, or revision checks were removed.
Remaining tasks
Final core committer review and commit.
User interface changes
None.
Introduced terminology
None.
API changes
None.
Data model changes
None.
Release notes snippet
Fixed a PostgreSQL error where nested SELECT queries during query alteration could throw "mimic_implicit_commit is already in use" inside a transaction.
| Comment | File | Size | Author |
|---|---|---|---|
| #89 | drupal-mimic_implicit_commit_error-2920527.patch | 724 bytes | oulalahakabu |
| #77 | drupal-mimic_implicit_commit_error-2920527-77.patch | 2.16 KB | liam morland |
Issue fork drupal-2920527
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
sylus commentedI am going to bump up the priority since essentially makes it impossible to save nodes while not an administrator.
Comment #3
sylus commentedComment #4
sylus commentedTo help this along I have replicated this with the following steps:
1) Install latest official / dev of Drupal 8.4.x
2) Install standard profile
3) Install + Enable small mimic_implicit module attached as a *.tgz
4) Add an editor user with the newly added editor role
5) Login as the newly created editor user w/editor role
6) Create a new piece of content of the newly added type "Landing"
You will recieve the error mentioned above and not be able to save the page
In essence my small module just adds an editor role + permissions + landing content type and simply adds the following hook:
Comment #5
sylus commentedI was hoping porting the following logic to workbench_moderation would have worked but to no avail:
#2821716: Fatal error when viewing node with content moderation enabled if a module which implements hook_node_grants() is enabled
Comment #6
sylus commentedHmm it doesn't seem like content_moderation has the same issue. I did trace the errors having to do with entityPresave() in workbench_moderation where this logic doesn't exist in content moderation entityPresave() anymore:
workbench moderation: http://cgit.drupalcode.org/workbench_moderation/tree/src/EntityOperation...
content moderation: http://cgit.drupalcode.org/drupal/tree/core/modules/content_moderation/s...
Can see a stack trace here: https://www.drupal.org/files/issues/behat-callstack.txt
Comment #8
volegerRelated #2981448: mimic_implicit_commit is already in use
Comment #11
logickal commentedWe are honestly not entirely sure what changed in 8.7.2 to cause this to start biting us, outside of it being some combination of view_unpublished and entityqueue modues interacting badly with something in the update. However, being bitten is a good way to start looking at a solution, so here is a patch that is a first pass at attempting to resolve this issue. I took the approach to move the $wrap_with_savepoint logic in pgsql\Connection wrapping to a public method, which allows it to be called by the pgsql\Select::execute() to determine whether or not to make that addSavepoint() call.
Comment #12
logickal commentedComment #13
rosk0Comment #14
aneek commentedApplied #11 patch, seems to work alright.
Comment #15
goldThe patch at #11 just saved me as well. Functionally it works, I have not had time to review the code though.
Comment #17
mradcliffeA couple of minor issues here with the patch.
I don't think we need this in core to point to an existing. issue. The functionality is already described in the database driver already.
I think this comment should be in the function comment above.
One thing I am curious to see is if there are more failed transactions or less during the Drupal install process with this patch (using minimal for sanity).
Comment #18
ravi.shankar commentedHere I have made changes as suggested in comment #17.
Comment #23
jakegibs617 commentedSeems like the module has changed structure significantly. I tried replicating the patch but it is still failing. Drupal core version 9.4.0 currently.
I have uploaded the in progress version of the patch but it currently has the error
Error: Call to undefined method Drupal\pgsql\Driver\Database\pgsql\Connection::wrapWithSavepoint() in Drupal\pgsql\Driver\Database\pgsql\Connection->query() (line 167 of /core/modules/pgsql/src/Driver/Database/pgsql/Connection.php).Comment #24
mradcliffeThank you for the patch, jakegibs617.
It's because this method got added to Upsert rather than Connection class.
Comment #25
jakegibs617 commentedOk for 9.4.0-dev Drupal core.
Attached is what seems to me as a working patch. Ready for others to review.
Comment #26
ankithashettyPatch in #25 had some issue, so rerolled the patch in #18 again. Also uploaded a diff file between #18 & #26 and a interdiff file between #25 & #26.
Thanks!
Comment #27
cilefen commentedComment #30
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
As a bug this will need a test case to show the issue.
Could the issue summary be updated to the default template showing proposed solution and remaining tasks please.
Tagged for manual testing for someone who uses postgresql.
Comment #32
smarchese commentedThanks @ankithashetty the patch #26 it's work for me!
Comment #33
abelassI can't apply #26 on 10.1
Comment #34
jakegibs617 commentedadding a remake of 2920527-26.patch but fitting to druapl 10.2.2
Comment #35
abelassThanks @jakegibs617 that works for me.
Comment #36
jakegibs617 commented@abelass are you able to clear the cache with the patch?
when I run drush cr
I am getting:
A transaction named mimic_implicit_commit is already in use. Active stack: 65b129b004e365.44430355\drupal_transaction > 65b129b020e3c2.42669084\mimic_implicit_commit
without the patch, if I log in as not an admin and edit a node then save I still see errors:
looks like transactionLayers was deprecated.
Comment #37
jakegibs617 commentedCan you give this one a shot? 2920527-37.patch
Comment #38
jakegibs617 commentedComment #39
abelass@jakegibs617 sorry for my late answer, we only could test the patch yesterday. #37 worked fine in our tests, thanks.
Comment #41
elimw commentedI updated Group contrib to 2.3.1 and noticed this issue. I applied patch #37 and even updated Core to 10.4.1 but neither fixed the issue.
Comment #43
vistree commentedI see the same error after upgrading groups module and trying to migrate user realationship.
I tried patch from #37 - but this does not solve the error for me.
Comment #45
dydave commentedThanks a lot Jake (@jakegibs617) for the contributed patch above at #37, the great documentation of the issue and getting the ball rolling with this patch.
I've tried to mention your work as much as possible in the MR to associate the credit.
Quick follow-up:
Created initial merge request above at #44:
1 - Rolled in patch from #37
2 - Added additional fix based on stack trace:
Mostly :
Drupal\pgsql\Driver\Database\pgsql\Schema->queryTableInformation('cache_flexible_permissions') (Line: 35)Tested and fixed issue in our project (similar versions mentioned above at #41) \o/
==> It probably still needs work, testing, but for now it fixes the issue in our project and allows us to move forward.
Any reviews and feedback would be greatly appreciated.
Thanks in advance!
Comment #46
vistree commented@dydave - is your MR expected to also solve the error on
Drupal\Core\Database\TransactionNameNonUniqueExceptionmentioned in #36 and #43?
Comment #47
dydave commentedThanks for the prompt feedback @vistree:
Really not sure about that, since we haven't come across this particular error.
Could you please try providing a backtrace, similar to the one above at #45?
Otherwise, perhaps more straight forward: Give the patch at:
https://git.drupalcode.org/project/drupal/-/merge_requests/10859.diff
a quick test and see if it fixes the issue in your project?
Thanks Matthew (@mradcliffe) for the help reviewing and cleaning up the MR.
Cheers!
Comment #48
elimw commentedI have pushed a change to fix the issue I was encountering.
Rather than having to explicitly check if we should wrap a query in a savepoint before calling "Connection::addSavepoint()", wouldn't it be better to do the check inside of "Connection::addSavepoint()" instead?
Comment #49
vistree commented@dydave - I found a backtrace in Watchdog. Is this helpfull? I am still on Drupal 10.4 by the way!! Therefor patch https://git.drupalcode.org/project/drupal/-/merge_requests/10859.diff will not apply.
Error appears when trying to migrate Group User Relations with drush migrate:
Drupal\Core\Database\TransactionNameNonUniqueException: A transaction named mimic_implicit_commit is already in use. Active stack: 677fb68df0dbc1.32969210\drupal_transaction > 677fb68df23611.91989256\mimic_implicit_commit in Drupal\Core\Database\Transaction\TransactionManagerBase->push() (Zeile 254 in /data/html/docroot/core/lib/Drupal/Core/Database/Transaction/TransactionManagerBase.php).Comment #50
dydave commentedNice one @vistree!
Just did the test with D10.4.1 and the patch applies very well.
Additionally, looking at your stack trace, see:
#3 /data/html/docroot/core/modules/pgsql/src/Driver/Database/pgsql/Upsert.php(35): Drupal\pgsql\Driver\Database\pgsql\Schema->queryTableInformation()Same as pointed above at #45.
Therefore: The patch should apply and fix the issue for your project! \o/
Could you please do a quick round of tests and report back?
Thanks in advance!
Comment #51
dydave commentedThanks Elim (@elimw), re #48:
Sounds good! I'm not super familiar with the overall code of the
pgsqlmodule, but if you do a quick search around and see where the functions are used and if there would be any unexpected impacts, it would be great!Could you perhaps create a new merge request with a different patch?
We would be able to give the patch a round of tests and see if it could be equivalent to the current MR!10859.
Thanks in advance!
Comment #52
vistree commented@dydave -After upgrading to current Drupal core 10.4.1 patch from MR (https://git.drupalcode.org/project/drupal/-/merge_requests/10859.diff) applied and - what great news - solved the error on running my migration ;-)
So, I can confirm that the MR solves the error regarding "Drupal\Core\Database\TransactionNameNonUniqueException" on group relationship migrations.
Comment #53
dydave commentedThanks a lot @vistree for the feedback! Glad it's working for you 🥳
Hopefully we'll get more reviews, feedback and perhaps a better version of the patch (see #51/refactoring), but for now, hopefully, this version will allow all of us to keep moving forward on our projects!
Cheers!
Comment #55
elimw commented@dydave, @vistree, I've created separate MR which checks if a savepoint with the same name already exists before pushing a transaction.
Comment #56
vistree commented@elimw: is your MR a replacement or an addition for MR 10859 ?
Comment #57
dydave commentedThanks a lot Elim (@elimw)! Great job!
We've just given a round of tests with the merge request you created MR!10896 and it fixed the issue as well for us 🥳
We've updated the patch in our project to use the one from #54.
@vistree:
Yes indeed, the patch created by Elim can be tested here:
https://git.drupalcode.org/project/drupal/-/merge_requests/10896.diff
It should fix the issue in your project as well.
It's a different (better) way of writing the same thing as the previous patch.
Thanks again for the work Elim and in advance for your feedback @vistree!
Comment #58
mradcliffeThe merge request 10896 (#45) seems to be 1770 commits behind the target branch and needs a rebase. It's currently failing tests.
The issue is a little hard to follow and I think next if someone could address the Needs issue summary update tag that would be helpful to clarify proposed resolutions and remaining tasks.
Comment #59
andrew.wang commentedhttps://git.drupalcode.org/project/drupal/-/merge_requests/10859.diff solved this issue for me after installing entity_reference_integrity on Drupal 10.3.10.
https://git.drupalcode.org/project/drupal/-/merge_requests/10896.diff also worked!
Comment #60
dydave commented@mradcliffe: Both merge requests have been rebased.
Since Elim's MR!10896 seems to fix the issue for us and is a much simpler version we would recommend going with this MR (Tests are passing 🟢).
Issue summary still needs to be updated.
Thanks!
Comment #61
vistree commentedI can confirm that also the MR https://git.drupalcode.org/project/drupal/-/merge_requests/10896.diff solves the error regarding "Drupal\Core\Database\TransactionNameNonUniqueException" on group relationship migrations.
Comment #62
smustgrave commentedWas previously tagged for IS update which still appears to be needed.
Also there are 2 MRs up so one needs to be closed or hidden.
Have not reviewed but will need test coverage is missing (whichever MR is picked)
Comment #64
dydave commentedAs per #62:
We're going with MR!10896 from #54 for now, so the other MR was hidden.
Still remaining to do if anyone has time to work on this issue: Write tests.
Create an automated test case allowing to reproduce the issue.
This would allow to better describe and summarize the IS, in particular with steps to reproduce or a piece of code that currently results in the Exception.
Elim (@elimw) perhaps if you find some time, it would be great if you could look into this and see if you could put together a small piece of code that could reproduce the exception (could be executed in devel_php, for example).
We could use it in an automated Test class added to the MR and then also document it in the IS.
Any help, advice or feedback would be greatly appreciated.
Thanks in advance!
Comment #65
elimw commented@dydave, I've added a PHPUnit test for the change and all tests are passing. I hope this is what you were after?
Sorry it's taken me so long to get around to doing this.
Comment #66
elimw commentedComment #67
andypostComment #68
dydave commentedSuper nice @elimw! Great job! 🥳
Looks like everything requested above is now in the MR, with the added Unit Test 👌
Let's see if reviewers and maintainers could take another look at this issue.
Thanks again for the great help and work @elimw!
Comment #69
m.stentaCan someone please update the issue summary to include an explanation of what the proposed change is to the logic, and why it is necessary? There are plenty of comments in this thread that say "the patch works!" but very little about what the broader implications of the change might be. Reading the code diff doesn't provide any of this, and it raises further questions.
Changing
if ($this->inTransaction()) {toif ($this->inTransaction() && !$this->transactionManager()->has($savepoint_name))means that theaddSavepoint()logic will NOT run in certain scenarios anymore. Is this OK? Has thought been given to how this might behave in other contexts? If so, I don't see any of that documented here (unless I missed it?) and if this causes issues later, future developers will have a hard time looking back at this issue and understanding why the decision was made.I'm not critiquing the solution itself - it might be the right answer! But I'd like to see more of an explanation so that it's easier to understand at a glance.
Setting back to "Needs work" for the issue summary update, per @smustgrave's comment #62 above.
Comment #70
m.stentapublic function addSavepoint($savepoint_name = 'mimic_implicit_commit')Very naively (having just jumped into this issue for the first time myself), could we leverage the
$savepoint_namemethod argument as a solution instead?It sounds like the issue is primarily a conflict in the
mimic_implicit_commitname itself. Presumably changing$savepoint_name = 'mimic_implicit_commit'to$savepoint_name = 'some_other_name'would also solve this problem? (I'm not suggesting that... just posing the thought.)I don't know all of the code that calls
addSavepoint(), but would it be possible to override that in the downstream modules that are affected by this issue, such that the default argument can be changed to avoid the conflict?Just throwing out alternative ideas here to stimulate the conversation a bit, while I wrap my head around this issue myself. Apologies if these have already been explored. :-)
Comment #73
liam morlandI have rebased this and did some work to get phpstan to pass.
Would it work to just use a different name for the save point? Instead of always using
mimic_implicit_commit, append a unique number,mimic_implicit_commit_1234.Comment #74
mradcliffeI like it. I am trying to remember if there was a reason not to do that back in 2015 or so. Whether the caller knew the transaction name or not.
Comment #75
liam morlandTests are passing.
It could be so that if the caller gives a name, it uses it. But if they do not, instead of always using
mimic_implicit_commit, it generates a unique name. Instead ofmimic_implicit_commitbeing the default for the$savepoint_nameparam, use null as the default. If it's null, generate the unique name.Comment #76
mondrakeAdding related issues.
Comment #77
liam morlandI have tested the merge request. It fixes the problem for me.
This patch is the current state of the merge request.
Comment #78
liam morlandSee #69 for notes about the issue summary update needed.
Comment #79
ironnuts commentedAdded a couple of minor comments in a code review.
Ran the manual 'Test-only' test. The output:
https://git.drupalcode.org/issue/drupal-2920527/-/jobs/9293971
LGTM. Seems the test coverage is failing as it should.
Comment #80
mondrakeI think @liam morland is right in #3583849-5: Deprecate PgSql Connection::*Savepoint() methods, and that issue is practically making this one outdated. #3583849: Deprecate PgSql Connection::*Savepoint() methods is solving this problem in a more generic way i.e. removing the savepoints array that is pgsql-specific, and managing the savepoints via the base TransactionManager. The TransactionManager already fails if a duplicate savepoint name is detected.
Comment #81
liam morland#3583849: Deprecate PgSql Connection::*Savepoint() methods has been resolved but the fix may just move the
mimic_implicit_commitproblem toConnection::query().Comment #82
mondrake#81 I do not think so, this code
already prevents to start a second savepoint named
mimic_implicit_commitif one exists, I think.If not, a test would help to show where the problem is, then.
Comment #83
liam morlandYes, I think you are right.
Comment #84
andypostLooks like it could be closed in favour of #3495728: [meta] Drop implicit autocommit on Transaction destruction
Comment #85
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. The merge request has merge conflicts and cannot be merged. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #86
liam morlandRerolled.
Comment #87
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #88
liam morland::addSavepoint()has been deprecated but code to start transactions calledmimic_implicit_commithas been added in a bunch of places. I am concerned that this may still lead to nested transactions with the same name.Comment #89
oulalahakabu commentedFastpatch from 10.6.x branch
Comment #90
dan3h commentedLiam, you are right that
mimic_implicit_commithas been added in other places. The TAC Lite module was triggering it for us today. I just made https://www.drupal.org/project/tac_lite/issues/3618911 for that problem, and posted a patch that works for it.Comment #93
jmcerdaAdded MR !17015 against main, adapting the savepoint-existence guard from !10859 to the current Select::execute() transaction API.
Reproduced on Drupal 11.4.6, PostgreSQL 16, PHP 8.4.22. An outer transaction plus a SELECT whose query-alter hook executes another SELECT throws TransactionNameNonUniqueException: mimic_implicit_commit is already in use. The new core-only regression reproduces this without contributed modules.
With the guard: Select suite 44 tests / 111 assertions; PostgreSQL transaction suite 21 tests / 271 assertions (2 existing skips). No failures. Dependency deprecations are reported. The regression also checks repeated nested queries, failed-query recovery, and rollback of the outer transaction.
The original moderated-node draft continuation scenario, with node grants and an existing node-reference field, changes from HTTP 500 to passing 30 functional assertions. No access, validation, or revision checks were removed. Main CI still needs verification; the local results above are for 11.4.6.
Comment #94
ironnuts commentedRan test-only test for MR!17015. https://git.drupalcode.org/issue/drupal-2920527/-/jobs/12007998. It fails on the new test code. Good sign.
Comment #95
jmcerdaThanks, oily, for running the test-only job. That confirms the new regression test fails without the fix.
With the fix applied, the PostgreSQL 18 / PHP 8.5 pipeline passed all automatic jobs: https://git.drupalcode.org/issue/drupal-2920527/-/pipelines/949568
The regression also checks repeated nested queries, recovery after a failed query, and rollback of the outer transaction. The original moderated-node draft creation and continuation scenario now passes with the patch on Drupal 11.4.6 / PostgreSQL 16 / PHP 8.4. No access, validation, or revision checks were removed.
Comment #96
ironnuts commentedAfter reading #95 setting to RTBTC.
Comment #97
ironnuts commentedComment #99
quietone commentedThis is tagged for an issue summary update and that should be done before setting to RTBC.
Comment #100
jmcerdaThanks, quietone. Updated the issue summary with the current reproduction, the savepoint guard in MR !17015, regression coverage, and the test-only and passing CI results. Replaced the stale implementation task with final committer review and commit, and removed the Needs issue summary update tag.
Comment #101
daffie commentedMaybe it would be better to remove all added savepoints. See: https://www.drupal.org/project/drupal/issues/3615690
Comment #102
ironnuts commentedRe: #101 daffie it would seem that this issue should be postponed pending https://www.drupal.org/project/drupal/issues/3615690 or closed as a duplicate. Re: #100 for example, we aren't going to need any savepoint guards when https://www.drupal.org/project/drupal/issues/3615690 lands.
daffie, Just wondering if there are any downsides to postgresql without savepoints or any reason to believe that we might end up having to use rely on them even if less than before? I noticed https://www.drupal.org/project/drupal/issues/3615690 is currently hitting test failures due to removal of savepoints (it looks like). Does that just mean fixing the tests to remove the savepoint-related code?
Comment #103
ironnuts commentedComment #104
jmcerdaI’ve contributed a rollback regression and draft correction to #3615690. Its proposed table-existence cache can retain an entry after rolling back table creation, causing subsequent operations to abort the transaction.
On #102: PostgreSQL still needs savepoints around failures that callers intend to catch and recover from inside a transaction. Removing blanket savepoints changes the recovery responsibilities of those callers; the tests need to verify that behavior.
#3615690 is marked major-version-only. Our reproduction here affects Drupal 11.4.6, so supported-branch handling remains relevant alongside the main-branch redesign. The smaller guard in !17015 remains available for that discussion.
Comment #105
phpsubbarao commentedWith Drupal 11.4.6 and Group 3.3.5, even after applying patch !17015, I am still encountering an error when adding a user to a group using the addMember() function
Comment #106
ironnuts commentedComment #107
andrew.wang commented@phpsubbarao Try https://git.drupalcode.org/project/drupal/-/merge_requests/10896.diff? This is the patch that solved my problem.
Comment #108
liam morland@#107 Merge request 10896 is changing a deprecated method, so I doubt it is a long-lasting solution.
Merge request 17015 fixes the issue for us. I have rebased this merge request.
Comment #109
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. The merge request has merge conflicts and cannot be merged. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #110
liam morlandThe conflict is in merge request 10896, which is closed.
Comment #111
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. The merge request has merge conflicts and cannot be merged. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #112
liam morlandTo prevent the bot from changing the status, I fixed the conflict in merge request 10896. I did not update the test.