-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hi all,
I'm using postmodern with great success but I keep seeing these two warnings in my log:
- "Postgres warning: there is no transaction in progress" - "Warning while processing connection: Postgres warning: there is already a transaction in progress"
As far as I can tell these are merely warnings but they're filling up my logs so I had a look at what was causing it and I found that save-dao has a (with-transaction () ...) wrapping an insert-dao and I was calling save-dao from within my own transaction block.
Now if just remove the with-transaction from save-dao an duplicate key violation will ruin the outer transaction by just aborting it (regardless of the error handling code. However if I add a savepoint just before trying insert-dao and in the error handling code use rollback-savepoint to restore to this savepoint I can make the warnings go away.
The problem now being that save-dao expects to be called within a with-transaction form. So I was wondering if there is some way to tell if we are within a transaction (e.g. within-transaction-p)? Then I would be able to make a modification that handles both cases.
It might then look something like this:
(defun save-dao (dao) (if (within-transaction-p) (with-savepoint save-dao (handler-case (progn (insert-dao dao) t) (cl-postgres-error:unique-violation () (rollback-savepoint save-dao) (update-dao dao) nil)))) (handler-case (with-transaction () (insert-dao dao) t) (cl-postgres-error:unique-violation () (update-dao dao) nil)))
Hello Peter,
It seems that transaction was a misguided attempt (apparently I believed postgres supported nested transactions at the time) to prevent the failure to insert from abandoning the transaction. I think the cleanest solution at this point is to add a variant, save-dao/transaction, that uses a savepoint, and declare the regular save-dao to only be safe outside of transactions.
I've pushed this change to the repository.
Best, Marijn
I've also had the need for determining the state of a transaction. Previously, I'd defined a local WITH-TRANSACTION macro that bound a special variable *TRANSACTION* with the transaction in progress.
I have attached a patch that does just that. WITHIN-TRANSACTION-P will return T if a transaction is open. I've not exported *TRANSACTION* because I'm unsure whether this should be part of the public interface. I'm yet to come up with a less hands-on approach to nested transactions, but this allows options for experiments outside of the postmodern proper.
For example, my ENSURE-TRANSACTION macro. Really, I should be using savepoints, but this allows me some more flexibility in how I layer my database access methods. I'm not sure if this is appropriate, but if you think it is useful enough, I can prepare a patch to include this as well.
(defmacro ensure-transaction ((&optional name) &body body) `(flet ((exec-body () (let ,(if name `((,name postmodern::*transaction*))) ,@body))) (if (within-transaction-p) (exec-body) (with-transaction (,name) (exec-body)))))
Hey Daniel,
I'd say something like this works best as a project-local hack, rather than part of the library interface. The user can perfectly well do (execute "begin") outside of the macro, causing the *transaction* variable to no longer reflect the actual situation.
Best, Marijn
On Tue, Mar 9, 2010 at 10:16 PM, Marijn Haverbeke marijnh@gmail.com wrote:
I'd say something like this works best as a project-local hack, rather than part of the library interface. The user can perfectly well do (execute "begin") outside of the macro, causing the *transaction* variable to no longer reflect the actual situation.
Maybe with a better docstring explicitly stating that it is limited to only knowing of transactions initiated with the WITH-TRANSACTION macro.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Marijn Haverbeke wrote:
Hey Daniel,
I'd say something like this works best as a project-local hack, rather than part of the library interface. The user can perfectly well do (execute "begin") outside of the macro, causing the *transaction* variable to no longer reflect the actual situation.
I agree that the pragmatic solution suggested is not a perfect one but I'm leaning this way myself since I'm using with-transaction very consistently. The best way would of course be if one could interrogate postgresql about its transaction state so that it could catch explicit statements like (execute "begin").
I implemented within-transaction-p using a special variable and a small modification to within-transaction to bind it and with these tools save-dao can be fixed for both when within and outside of a transaction without generating any warnings.
For me the problem with the explicit solution of save-dao and save-dao/transaction is that it can't be used to build any transaction agnostic abstractions.
Anyhow, this solution is good enough for now (and me). Thanks for all the input!
/Peter
Best, Marijn
postmodern-devel mailing list postmodern-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/postmodern-devel
postmodern-devel@common-lisp.net