Sometimes, when saving an entity (has happened with both indexes and facets up to now), I get an error screen showing the following message:

Error message
PDOException: SQLSTATE[42000]: Syntax error or access violation: 1305 SAVEPOINT savepoint_1 does not exist: RELEASE SAVEPOINT savepoint_1; Array ( ) in EntityAPIController->save() (line 141 of …/entity/entity/entity.db.inc).

Any idea why this could be?
The exception happens again when I go back and submit the form again, but not when I reload the form first (at least not reproducably).

Comments

drunken monkey’s picture

OK, it's not even reproducible when going back and re-submitting, it seems to be completely random.

fago’s picture

hm, I've never seen that, but I'd guess you manage to submit the same form again - maybe even while the first save is not yet finished, and so the transaction system avoids that?

drunken monkey’s picture

I have managed to arrive at a reproducable error, although it isn't reproducable in a sense in which I could tell others how to reproduce it — it's basically just an index where the error always occurs when I change the fields or the workflow (but, oddly enough, not normal settings).
So at least I can say that it's definitely nothing in the way I submit the form. I also now noticed that the changes actually get saved before the error occurs — when I go back and re-submit the form it doesn't produce an error simply because no save actually occurs.

I could of course always catch the PDOException and thus suppress the error from showing, but that's hardly the point of exceptions (and would possibly cover up other, real errors). In any case, if this would occur on a production site (or any site of a user that's not me) it would be seriously annoying to the user.

Could you maybe take a quick look at the save() and update() methods in SearchApiIndex and tell me if there could be anything the matter with them? Or maybe something to do with updated arrays / serialized values? I really don't know, nothing seems to be terribly extraordinary in the code …

In any event, it's oviously got something to do with the new transaction code, and it seems to me that somehow there is no valid transaction when the method returns and the system tries to commit the transaction. Although the transaction object is created, somehow the accompanying MySQL-level savepoint is not, or it is released earlier. Is there any situation where you think that might happen?
Maybe it's even a bug in the database layer — but I really don't know enough about that to make any informed guess.

blue56’s picture

I am also getting this exception when trying to add an Index in Search API.

Using:

D7 RC1
Search API (newest dev version)
Entity API (newest dev version)

fago’s picture

Strange, I've never faced problems with the transactions.

Perhaps try whether the following entity API controller change helps:

@@ -466,8 +466,8 @@ class EntityAPIController extends DrupalDefaultEntityControl
    *   Optionally a DatabaseTransaction object to use. Allows overrides to pass
    *   in their transaction object.
    */
-  public function save($entity, DatabaseTransaction $transaction = NULL) {
-    $transaction = isset($transaction) ? $transaction : db_transaction();
+  public function save($entity) {
+    $transaction = db_transaction();
     try {
       // Load the stored entity, if any.
       if (!empty($entity->{$this->nameKey}) && !isset($entity->original)) {

?

drunken monkey’s picture

Tested it, but it doesn't help.

Would be interesting to know whether this also occurs with a PSQL database …

fago’s picture

hm, there must be something in the search API that triggers that. Perhaps can try whether the problem appears with the "Entity" class too, and if not add in more and more of your adaptions?

drunken monkey’s picture

OK, after some research, the bug seems to be quite clear: When an index lies on a database server, hook_search_api_index_update() will lead (for field changes) to a db_set_active() call (because a database search server may use another than the default database) which apparently invalidates the transaction object. If I comment out just the $server->fieldsUpdated() call, everything works fine.

So, how could we fix this? I take it, it wouldn't be an option to commit the transaction (i.e., let the object go out of scope) before invoking the hooks? (Of course, this wouldn't work anyways when passing a transaction to the save() call …)

drunken monkey’s picture

See #1004332: db_set_active() commits transactions — maybe the database wizzes can tell us more about this.

drunken monkey’s picture

The problem isn't the db_set_active() call, but that tables are created and/or deleted, which automatically commits all transactions (and, seemingly, also releases all savepoints). But the result is the same: either we don't invoke the hooks while the transaction is running, or I'll have to modify the database service code to somehow circumvent this (and this caveat should probably be mentioned somewhere in the hook documentation).

You still haven't answered: Is it intended, that the hooks are invoked inside of the transaction?
Pro: Otherwise a transaction wouldn't have much sense, since the action itself is only a single database statement.
Contra: Any errors, exceptions or (as we see) just DDL statements in any other module's hook implementations cause the whole operation to fail (or an error screen to be displayed).

fago’s picture

Sry: Is it intended, that the hooks are invoked inside of the transaction?

Yes it is. As long as not all modules have finished their queries, the transaction is not complete. So we have to do it that way + core does it that way too.

fago’s picture

bojanz’s picture

Component: Entity CRUD API - main » Core integration
Issue summary: View changes
Status: Active » Closed (outdated)