[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*))
- [elpa] externals/pq 966a05ef25 07/63: Initialize client_encoding to utf8., (continued)
- [elpa] externals/pq 966a05ef25 07/63: Initialize client_encoding to utf8., ELPA Syncer, 2022/02/14
- [elpa] externals/pq 2f63308225 24/63: Use PQexec instead of PQexecParams when no parameters are specified., ELPA Syncer, 2022/02/14
- [elpa] externals/pq a70d1fe40d 37/63: Test encoding by using some high unicode codepoints., ELPA Syncer, 2022/02/14
- [elpa] externals/pq 795260553a 17/63: Use load-path in test.el, ELPA Syncer, 2022/02/14
- [elpa] externals/pq a03d2c2e9b 44/63: Update README, ELPA Syncer, 2022/02/14
- [elpa] externals/pq 12c54fbf15 14/63: Add undef DEFUN macro, ELPA Syncer, 2022/02/14
- [elpa] externals/pq 862bf023c0 20/63: Add processing for asynchronous notices., ELPA Syncer, 2022/02/14
- [elpa] externals/pq 9e719959b3 12/63: Avoid global variable for pq:error symbol., ELPA Syncer, 2022/02/14
- [elpa] externals/pq ca337173dd 08/63: Explicitly free the libpq result., ELPA Syncer, 2022/02/14
- [elpa] externals/pq e1d1b77b88 34/63: test: Notice receiver., ELPA Syncer, 2022/02/14
- [elpa] externals/pq 499dc3b50e 57/63: Re-introduce custom error signal pq:error with SQLSTATE.,
ELPA Syncer <=
- [elpa] externals/pq d738d21b6a 52/63: Add checks for non-local exit., ELPA Syncer, 2022/02/14
- [elpa] externals/pq 8151e0bc99 60/63: Add function pq:notifies to support LISTEN., ELPA Syncer, 2022/02/14
- [elpa] externals/pq 46e38888e3 01/63: Initial commit., ELPA Syncer, 2022/02/14
- [elpa] externals/pq b72ee45524 02/63: Add .gitignore, flush tempfile., ELPA Syncer, 2022/02/14
- [elpa] externals/pq dfa4ad04bb 03/63: README: clarify., ELPA Syncer, 2022/02/14
- [elpa] externals/pq 8e13d07737 16/63: Update Makefile, ELPA Syncer, 2022/02/14
- [elpa] externals/pq e9e1998796 10/63: Handle booleans and fix some NULL handling., ELPA Syncer, 2022/02/14
- [elpa] externals/pq 09e320f63f 29/63: Initial travis ci configuration, ELPA Syncer, 2022/02/14
- [elpa] externals/pq 76f81f5ca5 05/63: Replace low-level functions with a higher level one., ELPA Syncer, 2022/02/14
- [elpa] externals/pq 1048d41b99 28/63: Use pg_config to detect postgresql include directory, ELPA Syncer, 2022/02/14