aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2023-11-21 15:36:22 +0200
committerEli Zaretskii2023-11-21 15:36:22 +0200
commitd72a4ed65ce23581ff8b3bf4340caecf31c18f43 (patch)
treee29b9e83e4e9eeccfac0019eb268c8ce1d84eca1
parenta7b3c92373373f956234349fe6b792e1396e293e (diff)
downloademacs-d72a4ed65ce23581ff8b3bf4340caecf31c18f43.tar.gz
emacs-d72a4ed65ce23581ff8b3bf4340caecf31c18f43.zip
Fix 'with-sqlite-transaction' when BODY fails
* lisp/sqlite.el (with-sqlite-transaction): Don't commit changes if BODY errors out. Roll back the transaction if committing fails. (Bug#67142) * etc/NEWS: * doc/lispref/text.texi (Database): Document the error handling in 'with-sqlite-transaction'.
-rw-r--r--doc/lispref/text.texi6
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/sqlite.el21
3 files changed, 25 insertions, 7 deletions
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 4f11caaf64e..8fa2100ba11 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -5486,7 +5486,11 @@ made by the transaction.
5486 5486
5487@defmac with-sqlite-transaction db body@dots{} 5487@defmac with-sqlite-transaction db body@dots{}
5488Like @code{progn} (@pxref{Sequencing}), but executes @var{body} with a 5488Like @code{progn} (@pxref{Sequencing}), but executes @var{body} with a
5489transaction held, and commits the transaction at the end. 5489transaction held, and commits the transaction at the end if @var{body}
5490completes normally. If @var{body} signals an error, or committing the
5491transaction fails, the changes in @var{db} performed by @var{body} are
5492rolled back. The macro returns the value of @var{body} if it
5493completes normally and commit succeeds.
5490@end defmac 5494@end defmac
5491 5495
5492@defun sqlite-pragma db pragma 5496@defun sqlite-pragma db pragma
diff --git a/etc/NEWS b/etc/NEWS
index 1b3532b5657..333699f1015 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -62,6 +62,11 @@ of showing the shortcuts.
62 62
63* Incompatible Lisp Changes in Emacs 29.2 63* Incompatible Lisp Changes in Emacs 29.2
64 64
65+++
66** 'with-sqlite-transaction' rolls back changes if its BODY fails.
67If the BODY of the macro signals an error, or committing the results
68of the transaction fails, the changes will now be rolled back.
69
65 70
66* Lisp Changes in Emacs 29.2 71* Lisp Changes in Emacs 29.2
67 72
diff --git a/lisp/sqlite.el b/lisp/sqlite.el
index aad0aa40fa4..8a525739c9a 100644
--- a/lisp/sqlite.el
+++ b/lisp/sqlite.el
@@ -24,19 +24,28 @@
24;;; Code: 24;;; Code:
25 25
26(defmacro with-sqlite-transaction (db &rest body) 26(defmacro with-sqlite-transaction (db &rest body)
27 "Execute BODY while holding a transaction for DB." 27 "Execute BODY while holding a transaction for DB.
28If BODY completes normally, commit the changes and return
29the value of BODY.
30If BODY signals an error, or transaction commit fails, roll
31back the transaction changes."
28 (declare (indent 1) (debug (form body))) 32 (declare (indent 1) (debug (form body)))
29 (let ((db-var (gensym)) 33 (let ((db-var (gensym))
30 (func-var (gensym))) 34 (func-var (gensym))
35 (res-var (gensym))
36 (commit-var (gensym)))
31 `(let ((,db-var ,db) 37 `(let ((,db-var ,db)
32 (,func-var (lambda () ,@body))) 38 (,func-var (lambda () ,@body))
39 ,res-var ,commit-var)
33 (if (sqlite-available-p) 40 (if (sqlite-available-p)
34 (unwind-protect 41 (unwind-protect
35 (progn 42 (progn
36 (sqlite-transaction ,db-var) 43 (sqlite-transaction ,db-var)
37 (funcall ,func-var)) 44 (setq ,res-var (funcall ,func-var))
38 (sqlite-commit ,db-var)) 45 (setq ,commit-var (sqlite-commit ,db-var))
39 (funcall ,func-var))))) 46 ,res-var)
47 (or ,commit-var (sqlite-rollback ,db-var))))
48 (funcall ,func-var))))
40 49
41(provide 'sqlite) 50(provide 'sqlite)
42 51