Last modified: 2014-06-23 16:07:11 UTC
The problem in a nutshell is: - I try to create an account via an API call - All the queries run successfully and the result is "success" - At the end of the whole process MediaWiki closes connection without doing a COMMIT thus losing all previous actions The problem detailed: 1.) I use the following code for creating a new account: <?php $nick = 'test45'; $pwd = 'aaaaaa'; $email = 'valid@example.com'; $user = make_fake_request( array( 'action' => 'createaccount', 'name' => $nick, 'password' => $pwd, 'email' => $email, 'token' => '' )); if (isset($user['createaccount']) && $user['createaccount']['result'] == 'needtoken') { $user = make_fake_request( // Felhasználó regisztrálása array( 'action' => 'createaccount', 'name' => $nick, 'password' => $pwd, 'email' => $email, 'token' => $user['createaccount']['token'] )); if (isset($user['createaccount']) && $user['createaccount']['result'] == 'success') { echo "OK"; } } ?> The "make_fake_request" function consist of the following: <?php require_once ("$IP/includes/WebStart.php"); global $wgRequest; $request = new DerivativeRequest($wgRequest, $params, true); $api = new ApiMain($request, true); $api->execute(); $x = & $api->getResultData(); return $x; ?> This echoes me "OK" all the time when I fill it with valid data. 2.) In the MySQL query log the following runs: Connect Init DB Query SET /* DatabaseMysql::open */ NAMES utf8 Query SET /* DatabaseMysql::open */ sql_mode = '' Query BEGIN /* DatabaseBase::query (Title::getCascadeProtectionSources) */ Query SELECT /* Title::getCascadeProtectionSources [...] FROM `templatelinks`,`page_restrictions`,`page` WHERE [...] Query SELECT /* Block::newLoad [...] FROM `ipblocks` WHERE [...] Query SELECT /* Block::newLoad [...] FROM `ipblocks` WHERE [...] Query SELECT /* Title::getCascadeProtectionSources [...] FROM `templatelinks`,`page_restrictions`,`page` WHERE [...] Query SELECT /* Title::getCascadeProtectionSources [...] FROM `templatelinks`,`page_restrictions`,`page` WHERE [...] Query SELECT /* User::idForName [...] FROM `user` WHERE [...] Query SELECT /* User::idFromName [...] FROM `user` WHERE [...] Query INSERT /* User::addToDatabase */ IGNORE INTO `user` [...] Query SELECT /* User::loadOptions [...] FROM `user_properties` WHERE [...] Query DELETE /* User::saveOptions */ FROM `user_properties` WHERE [...] Query UPDATE /* User::saveSettings */ `user` SET [...] Query DELETE /* User::saveOptions */ FROM `user_properties` WHERE [...] Query INSERT /* User::saveOptions */ INTO `user_properties` [...] Query UPDATE /* Title::invalidateCache */ `page` SET [...] Query SELECT /* WikiPage::pageData [...] FROM `page` WHERE [...] Query UPDATE /* User::saveSettings */ `user` [...] Query DELETE /* User::saveOptions */ FROM `user_properties` WHERE [...] Query INSERT /* User::saveOptions */ INTO `user_properties` [...] Query UPDATE /* Title::invalidateCache */ `page` [...] Query SELECT /* WikiPage::pageData [...] FROM `page` WHERE [...] Query INSERT /* ManualLogEntry::insert */ INTO `logging` [...] Query SELECT /* User::idFromName [...] FROM `user` WHERE [...] Query SELECT /* User::loadGroups [...] FROM `user_groups` WHERE [...] Query SELECT /* User::getEditCount [...] FROM `user` WHERE [...] Query INSERT /* RecentChange::save */ INTO `recentchanges` [...] Query SELECT /* EmailNotification::notifyOnPageChange [...] FROM `watchlist` WHERE [...] Quit 3.) As you can see above, there's no COMMIT at the end, so all of the changes will be rolled back as soon as the PHP is closing its connection. The SQL server is MySQL v5.5.30.
In this case it really needs to call $user->addToDatabase() somewhere near to the end CC'ing named author of the file Andre: When we have a fix committed etc, this should most definitely be backported to all applicable branches. I'm not sure how widely it's actually used, but a maintenance release could be in order too
https://git.wikimedia.org/history/mediawiki%2Fcore.git/7113a5d0a5592c016f6dd57e1de002b8263c0bc9/includes%2Fapi%2FApiCreateAccount.php Thanks for reporting this issue btw
(In reply to comment #1) > In this case it really needs to call $user->addToDatabase() somewhere near to > the end Looking closer (and more awake), the dangling transaction starts in Title::getCascadeProtectionSources(), which manifests itself as such. Might not be the API module. In master "getCascadeProtectionSources" doesn't call a begin(), neither does it open a connection to a DB Master
To be specific, the transaction starts in "DatabaseBase::query (Title::getCascadeProtectionSources)". The actual method says DatabaseBase::query, which means this is an automatically started transaction (so DBO_TRX is set here). As for why the implicit transaction is not committing, I'm not too sure, because DatabaseBase::close() automatically commits transactions before it closes the DB connection.
(In reply to comment #1) > Andre: When we have a fix committed etc, this should most definitely be > backported to all applicable branches. I'm not sure how widely it's actually > used, but a maintenance release could be in order too ==> Setting Backport flag to "requested" (which is "?") and CC'ing hexmode.
Out of interest, what version of PHP are you running? On what platform?
PHP v5.3.17 on an openSUSE 12.3 x64.
This doesn't seem to be an API issue. The issue is that the DBO_TRX transaction is never getting closed. And it looks to me that the problem is that the reporter's weird script is not bothering to call LoadBalancer::shutdown(), which would make this bug RESOLVED INVALID. (In reply to comment #0) > The problem in a nutshell is: > - I try to create an account via an API call That's not what you're doing here. You're creating an account from a script that is poking at MediaWiki in a non-standard manner. > - At the end of the whole process MediaWiki closes connection without doing a > COMMIT thus losing all previous actions Also wrong. You're never telling MediaWiki to actually close the connection. Try adding the following to the end of your script and see if it works: DeferredUpdates::doUpdates(); $lb = wfGetLBFactory(); $lb->shutdown(); (In reply to comment #1) > In this case it really needs to call $user->addToDatabase() somewhere near to > the end That's being called in LoginForm::initUser(), which is called from LoginForm::addNewAccountInternal(), which is called from ApiCreateAccount to do the actual user creation.
Thank you for the advice. Adding the suggested lines into the code makes it work perfectly. Well, how standard it is, I don't know. I made this code a year ago (it wasn't so long after all) based entirely upon the official guide [1] with the help of an other page (also recommended inside the guide) [2]. Time flew and it was a mistake not to complete my code with the required changes. Sorry for the false report and thank you for the quick response. I closed it as invalid. [1]: http://www.mediawiki.org/w/index.php? title=API:Calling_internally&oldid=536426 [2]: http://web.archive.org/web/20120626061757/http://auzigog.com/2009/01/11/creating-a-mediawiki-api-instance-outside-installation-directory/
(In reply to comment #9) > Well, how standard it is, I don't know. I made this code a year ago (it > wasn't > so long after all) based entirely upon the official guide [1] with the help > of > an other page (also recommended inside the guide) [2]. The first is for calling the API from within MediaWiki, if for some reason that's necessary. But in that case, the standard MediaWiki entry points will have the code to clean things up properly. The second, unfortunately, appears to have been some random guy spamming a link to his blog. Ideally either your script should access the API through a web request to api.php or it should be done as a proper maintenance script.[3] [3]: https://www.mediawiki.org/wiki/Manual:Writing_maintenance_scripts
Oh, I see. Thank you for pointing this out. I think if I have a bit more time, I'll rewrite my script using the standard api.php. Thank you again for your time.