emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/pq 499dc3b50e 57/63: Re-introduce custom error signal p


From: ELPA Syncer
Subject: [elpa] externals/pq 499dc3b50e 57/63: Re-introduce custom error signal pq:error with SQLSTATE.
Date: Mon, 14 Feb 2022 23:24:27 -0500 (EST)

branch: externals/pq
commit 499dc3b50e5963c939b20cab063855a0f7afb969
Author: Andreas Seltenreich <seltenreich@gmx.de>
Commit: Andreas Seltenreich <seltenreich@gmx.de>

    Re-introduce custom error signal pq:error with SQLSTATE.
---
 README.org | 15 ++++++++++++++-
 pq.c       | 26 ++++++++++++++++++++++----
 test.el    | 13 ++++++++++++-
 3 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/README.org b/README.org
index cf3433bb72..6a14d519de 100644
--- a/README.org
+++ b/README.org
@@ -29,7 +29,20 @@ Basic usage:
 :  ["font-lock-major-mode" 24]
 :  ["font-lock-mode-major-mode" 24])
 
-See the testsuite [[./test.el]] for all implemented features.
+
+=pq= raises SQL errors as error signal =pq:error=.  This provides the
+[[https://www.postgresql.org/docs/current/errcodes-appendix.html][SQLSTATE]] 
error code in an additional string in the error data list.
+For example, you can reliably catch unique violations like this:
+
+: (condition-case err (pq:query *pq* "insert into t values (666)")
+:   (pq:error
+:    (if (string= "23505" (nth 2 err))
+:        (progn
+:       (message "Caught a unqiue violation"))
+:      ;; re-throw anything else
+:      (signal (car err) (cdr err)))))
+
+See the testsuite [[./test.el]] for more implemented features.
 
 Note that =pq= silently converts bigints and numerics your queries
 return to lisp floats because they don't fit into a lisp integer.
diff --git a/pq.c b/pq.c
index 7b1cefd18d..ecff3bfd45 100644
--- a/pq.c
+++ b/pq.c
@@ -51,12 +51,18 @@ static bool result_ok(emacs_env *env, PGresult *res)
   default:
     {
       const char *errmsg = PQresultErrorMessage(res);
-      emacs_value errstring = env->make_string(env, errmsg, strlen(errmsg));
-      emacs_value Qpq_error = env->intern (env, "error");
-      emacs_value errdata = env->funcall(env, env->intern(env, "list"), 1, 
&errstring);
+      const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
+      emacs_value Qpq_error = env->intern (env, "pq:error");
+      emacs_value errmsg_string =
+          env->make_string(env, errmsg, strlen(errmsg));
+      emacs_value sqlstate_string =
+          env->make_string(env, sqlstate, strlen(sqlstate));
+      emacs_value errdata[] = {errmsg_string, sqlstate_string};
+      emacs_value errdata_list =
+          env->funcall(env, env->intern(env, "list"), 2, errdata);
 
       PQclear(res);
-      env->non_local_exit_signal(env, Qpq_error, errdata);
+      env->non_local_exit_signal(env, Qpq_error, errdata_list);
     }
     return false;
   }
@@ -386,6 +392,18 @@ emacs_module_init (struct emacs_runtime *ert)
 
 #undef DEFUN
 
+  /* Define custom error signal.  The error data is a list with two
+   * strings.  The first string is the human-readable message, the
+   * second is the SQLSTATE error code. */
+  {
+       emacs_value Fdefine_error = env->intern (env, "define-error");
+       emacs_value Qpq_error = env->intern (env, "pq:error");
+       emacs_value errmsg_string =
+           env->make_string(env, "SQL error", strlen("SQL error"));
+       emacs_value args[] = {Qpq_error, errmsg_string};
+       env->funcall(env, Fdefine_error, 2, args);
+  }
+
   provide(env, "pq");
 
   /* loaded successfully */
diff --git a/test.el b/test.el
index 956f9bb4c5..68d84a2735 100644
--- a/test.el
+++ b/test.el
@@ -73,7 +73,18 @@
     (pq:query conn "select 1")
     (should-error (pq:query "select * from"))
     (should-error (pq:query conn "select * from"))
-    (should-error (pq:query conn "select $1::text"))))
+    (should-error (pq:query conn "select $1::text"))
+    (should
+     (equal
+      'ok
+      (condition-case err
+         (pq:query conn "moo")
+       (pq:error
+        (if (string= "42601" (nth 2 err))
+            ;; syntax errors are ok
+            'ok
+          (signal (car err) (cdr err)))))))
+))
 
 (ert-deftest pq-reset-connection-test ()
   (let ((testconn (pq:connectdb *conninfo*))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]