branch: elpa/pg
commit 5063ec8bb8679ba40b1423b6cc1b086cfb735803
Author: Eric Marsden <[email protected]>
Commit: Eric Marsden <[email protected]>
Document the password-as-zero-arg-function support
---
doc/src/API.md | 31 ++++++++++++++++++++------
pg.el | 68 ++++++++++++++++++++++++++++++++--------------------------
2 files changed, 61 insertions(+), 38 deletions(-)
diff --git a/doc/src/API.md b/doc/src/API.md
index b13c47d4c8e..62b3e08d524 100644
--- a/doc/src/API.md
+++ b/doc/src/API.md
@@ -4,10 +4,10 @@
The entry points in the pg-el library are documented below.
- (with-pg-connection con (dbname user [password host port]) &body body)
+ (with-pg-connection-plist con (dbname user &key args) &body body)
A macro which opens a TCP network connection to database `DBNAME`, executes
the `BODY` forms then
-disconnects. See function `pg-connect` for details of the connection arguments.
+disconnects. See function `pg-connect-plist` for details of the connection
arguments `ARGS`.
(with-pg-connection-local con (path dbname user [password]) &body body)
@@ -23,13 +23,16 @@ A macro which executes the `BODY` forms wrapped in an SQL
transaction. `CON` is
database. If an error occurs during the execution of the forms, a ROLLBACK
instruction is executed.
- (pg-connect dbname user [password host port tls-options]) -> con
+ (pg-connect-plist dbname user &key password host port tls-options
direct-tls server-variant protocol-version) -> con
Connect to the database `DBNAME` on `HOST` (defaults to localhost) at `PORT`
(defaults to 5432) via
-TCP/IP and authenticate as `USER` with `PASSWORD`. This library currently
supports SCRAM-SHA-256
-authentication (the default method from PostgreSQL version 14 onwards), MD5
authentication and
-cleartext password authentication. This function also sets the output date
type to `ISO` and
-initializes our type parser tables.
+TCP/IP and authenticate as `USER` with `PASSWORD`. `PASSWORD` may be a string,
or a zero-argument
+lambda function which returns the password as a string (this makes it possible
to use the
+auth-source functionality in Emacs). This library currently supports
SCRAM-SHA-256 authentication
+(the default method from PostgreSQL version 14 onwards), MD5 authentication
and cleartext password
+authentication.
+
+This function also sets the output date type to `ISO` and initializes our type
parser tables.
If `tls-options` is non-NIL, attempt to establish an encrypted connection to
PostgreSQL by
passing `tls-options` to Emacs function `gnutls-negotiate`. `tls-options` is a
Common-Lisp style
@@ -49,6 +52,20 @@ form
where `key` is the filename of the client certificate private key and `cert`
is the filename of the
client certificate. These are passed to GnuTLS.
+If argument `direct-tls` is non-NIL, attempt to establish a “direct” TLS
connection to PostgreSQL,
+as supported since PostgreSQL version 18. This saves a few network packets
during the establishment
+of a network connection. This connection mode uses ALPN and requires ALPN
support in your Emacs (in
+testing as of Emacs 30).
+
+If argument `server-variant` is non-NIL, force the detected value of
`pgcon-server-variant` to the
+specified value. This may be needed for some PostgreSQL variants that we are
not able to identify
+via their version string and startup options, but for which we need to
implement workarounds (the
+primary culprit is currently Clickhouse).
+
+If `protocol-version` is non-NIL, it should be a `(major-version .
minor-version)` cons representing
+the version of the PostgreSQL wire protocol to use. Currently `major-version`
should be 3 and
+`minor-version` should be 0 or 2.
+
(pg-connect-local path dbname user [password]) -> con
diff --git a/pg.el b/pg.el
index 28b0f9edc98..c5a9d2858c5 100644
--- a/pg.el
+++ b/pg.el
@@ -796,14 +796,14 @@ Uses database DBNAME, user USER and password PASSWORD."
;; AUTH_REQ_CLEARTEXT_PASSWORD
(3
- ;; send a PasswordMessage
- (let ((actual-password (if (functionp password)
- (funcall password)
- password)))
- (pg-send-char con ?p)
- (pg-send-uint con (+ 5 (length actual-password)) 4)
- (pg-send-string con actual-password))
- (pg-flush con))
+ ;; send a PasswordMessage
+ (let ((password-string (if (functionp password)
+ (funcall password)
+ password)))
+ (pg-send-char con ?p)
+ (pg-send-uint con (+ 5 (length password-string)) 4)
+ (pg-send-string con password-string))
+ (pg-flush con))
;; AUTH_REQ_CRYPT
(4
@@ -926,9 +926,10 @@ Uses database DBNAME, user USER and password PASSWORD."
(server-variant nil)
(protocol-version (cons 3 0)))
"Initiate a connection with the PostgreSQL backend over TCP.
-Connect to the database DBNAME with the username USER, on PORT of
-HOST, providing PASSWORD if necessary. Return a connection to the
-database (as an opaque type). PORT defaults to 5432, HOST to
+Connect to the database DBNAME with the username USER, on PORT of HOST,
+providing PASSWORD if necessary. PASSWORD may be either a string or a
+zero-argument function which returns a string. Return a connection to
+the database (as an opaque type). PORT defaults to 5432, HOST to
\"localhost\", and PASSWORD to an empty string.
If TLS-OPTIONS is non-NIL, attempt to establish an encrypted connection
@@ -1064,8 +1065,9 @@ to use the updated protocol features introduced with
PostgreSQL version
(tls-options nil)
(server-variant nil))
"Initiate a connection with the PostgreSQL backend over TCP.
-Connect to the database DBNAME with the username USER, on PORT of
-HOST, providing PASSWORD if necessary. Return a connection to the
+Connect to the database DBNAME with the username USER, on PORT of HOST,
+providing PASSWORD if necessary. PASSWORD may be a either string, or a
+zero-argument function that returns a string. Return a connection to the
database (as an opaque type). PORT defaults to 5432, HOST to
\"localhost\", and PASSWORD to an empty string. If TLS-OPTIONS is
non-NIL, attempt to establish an encrypted connection to PostgreSQL
@@ -1098,11 +1100,12 @@ you would like to run specific code in
(port 5432)
(tls-options nil))
"Initiate a direct TLS connection with the PostgreSQL backend over TCP.
-Connect to the database DBNAME with the username USER, on PORT of
-HOST, providing PASSWORD if necessary. Return a connection to the
-database (as an opaque type). PORT defaults to 5432, HOST to
-\"localhost\", and PASSWORD to an empty string. The TLS-OPTIONS
-are passed to GnuTLS."
+Connect to the database DBNAME with the username USER, on PORT of HOST,
+providing PASSWORD if necessary. PASSWORD may be either a string, or a
+zero-argument function that returns a string. Return a connection to
+the database (as an opaque type). PORT defaults to 5432, HOST to
+\"localhost\", and PASSWORD to an empty string. The TLS-OPTIONS are
+passed to GnuTLS."
(declare (obsolete pg-connect-plist "2025"))
(pg-connect-plist dbname user
:password password
@@ -1114,8 +1117,9 @@ are passed to GnuTLS."
(cl-defun pg-connect-local (path dbname user &optional (password ""))
"Initiate a connection with the PostgreSQL backend over local Unix socket
PATH.
Connect to the database DBNAME with the username USER, providing
-PASSWORD if necessary. Return a connection to the database (as an
-opaque type). PASSWORD defaults to an empty string."
+PASSWORD if necessary. PASSWORD may be either a string, or a
+zero-argument function that returns a string. Return a connection to the
+database (as an opaque type). PASSWORD defaults to an empty string."
(let* ((buf (generate-new-buffer " *PostgreSQL*"))
(process (make-network-process :name "postgres"
:buffer buf
@@ -3514,12 +3518,13 @@ Respects floating-point infinities and NaN."
;; hash = ′md5′ + md5(pwdhash + salt).hexdigest()
(defun pg-do-md5-authentication (con user password)
"Attempt MD5 authentication with PostgreSQL database over connection CON.
-Authenticate as USER with PASSWORD."
- (let* ((actual-password (if (functionp password)
- (funcall password)
- password))
+Authenticate as USER with PASSWORD, which is either a string or a
+zero-argument function that returns a string."
+ (let* ((password-string (if (functionp password)
+ (funcall password)
+ password))
(salt (pg-read-chars con 4))
- (pwdhash (md5 (concat actual-password user)))
+ (pwdhash (md5 (concat password-string user)))
(hash (concat "md5" (md5 (concat pwdhash salt)))))
(pg-send-char con ?p)
(pg-send-uint con (+ 5 (length hash)) 4)
@@ -3592,7 +3597,7 @@ Authenticate as USER with PASSWORD."
;; https://www.rfc-editor.org/rfc/rfc7677
(defun pg-do-scram-sha256-authentication (con user password)
"Attempt SCRAM-SHA-256 authentication with PostgreSQL over connection CON.
-Authenticate as USER with PASSWORD."
+Authenticate as USER with PASSWORD, a string."
(let* ((mechanism "SCRAM-SHA-256")
(client-nonce (or pg--*force-client-nonce*
(apply #'string (cl-loop for i below 32 collect (+
?A (random 25))))))
@@ -3686,17 +3691,18 @@ Authenticate as USER with PASSWORD."
(defun pg-do-sasl-authentication (con user password)
"Attempt SASL authentication with PostgreSQL over connection CON.
-Authenticate as USER with PASSWORD."
- (let ((actual-password (if (functionp password)
- (funcall password)
- password))
+Authenticate as USER with PASSWORD, which is either a string or a
+zero-argument function that returns a string."
+ (let ((password-string (if (functionp password)
+ (funcall password)
+ password))
(mechanisms (list)))
;; read server's list of preferered authentication mechanisms
(cl-loop for mech = (pg-read-string con 4096)
while (not (zerop (length mech)))
do (push mech mechanisms))
(if (member "SCRAM-SHA-256" mechanisms)
- (pg-do-scram-sha256-authentication con user actual-password)
+ (pg-do-scram-sha256-authentication con user password-string)
(let ((msg (format "Can't handle any of SASL mechanisms %s" mechanisms)))
(signal 'pg-protocol-error (list msg))))))