PageRenderTime 191ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/db-postgresql-socket/postgresql-socket-api.lisp

https://github.com/UnwashedMeme/clsql
Lisp | 973 lines | 845 code | 93 blank | 35 comment | 25 complexity | be7293ef3f885ffda9be6fedee7ad7b5 MD5 | raw file
Possible License(s): LGPL-3.0, CC-BY-SA-3.0
  1. ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
  2. ;;;; *************************************************************************
  3. ;;;; FILE IDENTIFICATION
  4. ;;;;
  5. ;;;; Name: postgresql-socket-api.lisp
  6. ;;;; Purpose: Low-level PostgreSQL interface using sockets
  7. ;;;; Authors: Kevin M. Rosenberg based on original code by Pierre R. Mai
  8. ;;;; Created: Feb 2002
  9. ;;;;
  10. ;;;; This file, part of CLSQL, is Copyright (c) 2002-2010 by Kevin M. Rosenberg
  11. ;;;; and Copyright (c) 1999-2001 by Pierre R. Mai
  12. ;;;;
  13. ;;;; CLSQL users are granted the rights to distribute and use this software
  14. ;;;; as governed by the terms of the Lisp Lesser GNU Public License
  15. ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
  16. ;;;; *************************************************************************
  17. (in-package #:postgresql-socket)
  18. ;; KMR: 2011-06-12
  19. ;; FIXME: The file has code specific to sb-unicode and CCL
  20. ;; to assume UTF8 encoded strings.
  21. ;; Best fix would be to use the user-specified encoding that is now
  22. ;; stored in the database object and use the UFFI 2.x encoding functions
  23. ;; to convert strings to/from octet vectors. This allows encoding
  24. ;; other than UTF8 and also works on all CL implementations that
  25. ;; support wide character strings
  26. (uffi:def-enum pgsql-ftype
  27. ((:bytea 17)
  28. (:int2 21)
  29. (:int4 23)
  30. (:int8 20)
  31. (:float4 700)
  32. (:float8 701)))
  33. (defmethod clsql-sys:database-type-library-loaded ((database-type
  34. (eql :postgresql-socket)))
  35. "T if foreign library was able to be loaded successfully. Always true for
  36. socket interface"
  37. t)
  38. (defmethod clsql-sys:database-type-load-foreign ((database-type (eql :postgresql-socket)))
  39. t)
  40. ;;; Message I/O stuff
  41. (defmacro define-message-constants (description &rest clauses)
  42. (assert (evenp (length clauses)))
  43. (loop with seen-characters = nil
  44. for (name char) on clauses by #'cddr
  45. for char-code = (char-code char)
  46. for doc-string = (format nil "~A (~:C): ~A" description char name)
  47. if (member char seen-characters)
  48. do (error "Duplicate message type ~@C for group ~A" char description)
  49. else
  50. collect
  51. `(defconstant ,name ,char-code ,doc-string)
  52. into result-clauses
  53. and do (push char seen-characters)
  54. finally
  55. (return `(progn ,@result-clauses))))
  56. (eval-when (:compile-toplevel :load-toplevel :execute)
  57. (define-message-constants "Backend Message Constants"
  58. +ascii-row-message+ #\D
  59. +authentication-message+ #\R
  60. +backend-key-message+ #\K
  61. +binary-row-message+ #\B
  62. +completed-response-message+ #\C
  63. +copy-in-response-message+ #\G
  64. +copy-out-response-message+ #\H
  65. +cursor-response-message+ #\P
  66. +empty-query-response-message+ #\I
  67. +error-response-message+ #\E
  68. +function-response-message+ #\V
  69. +notice-response-message+ #\N
  70. +notification-response-message+ #\A
  71. +ready-for-query-message+ #\Z
  72. +row-description-message+ #\T))
  73. #+scl
  74. (declaim (inline read-byte write-byte))
  75. (defun send-socket-value-int32 (socket value)
  76. (declare (type stream socket)
  77. (type (unsigned-byte 32) value))
  78. (write-byte (ldb (byte 8 24) value) socket)
  79. (write-byte (ldb (byte 8 16) value) socket)
  80. (write-byte (ldb (byte 8 8) value) socket)
  81. (write-byte (ldb (byte 8 0) value) socket)
  82. nil)
  83. (defun send-socket-value-int16 (socket value)
  84. (declare (type stream socket)
  85. (type (unsigned-byte 16) value))
  86. (write-byte (ldb (byte 8 8) value) socket)
  87. (write-byte (ldb (byte 8 0) value) socket)
  88. nil)
  89. (defun send-socket-value-int8 (socket value)
  90. (declare (type stream socket)
  91. (type (unsigned-byte 8) value))
  92. (write-byte (ldb (byte 8 0) value) socket)
  93. nil)
  94. (defun send-socket-value-char-code (socket value)
  95. (declare (type stream socket)
  96. (type character value))
  97. (write-byte (ldb (byte 8 0) (char-code value)) socket)
  98. nil)
  99. (defun send-socket-value-string (socket value)
  100. (declare (type stream socket)
  101. (type string value))
  102. #-(or sb-unicode ccl)
  103. (loop for char across value
  104. for code = (char-code char)
  105. do (write-byte code socket)
  106. finally (write-byte 0 socket))
  107. #+ccl
  108. (write-sequence (ccl:encode-string-to-octets
  109. value :external-format :utf-8) socket)
  110. #+ccl
  111. (write-byte 0 socket)
  112. #+sb-unicode
  113. (write-sequence (sb-ext:string-to-octets value :null-terminate t)
  114. socket)
  115. nil)
  116. (defun send-socket-value-limstring (socket value limit)
  117. (declare (type stream socket)
  118. (type string value)
  119. (type fixnum limit))
  120. (let ((length (length value)))
  121. (dotimes (i (min length limit))
  122. (let ((code (char-code (char value i))))
  123. (write-byte code socket)))
  124. (dotimes (i (- limit length))
  125. (write-byte 0 socket)))
  126. nil)
  127. (defun read-socket-value-int32 (socket)
  128. (declare (type stream socket))
  129. (declare (optimize (speed 3)))
  130. (let ((result 0))
  131. (declare (type (unsigned-byte 32) result))
  132. (setf (ldb (byte 8 24) result) (read-byte socket))
  133. (setf (ldb (byte 8 16) result) (read-byte socket))
  134. (setf (ldb (byte 8 8) result) (read-byte socket))
  135. (setf (ldb (byte 8 0) result) (read-byte socket))
  136. result))
  137. (defun read-socket-value-int16 (socket)
  138. (declare (type stream socket))
  139. (let ((result 0))
  140. (declare (type (unsigned-byte 16) result))
  141. (setf (ldb (byte 8 8) result) (read-byte socket))
  142. (setf (ldb (byte 8 0) result) (read-byte socket))
  143. result))
  144. (defun read-socket-value-int8 (socket)
  145. (declare (type stream socket))
  146. (read-byte socket))
  147. (defun read-socket-value-string (socket)
  148. (declare (type stream socket))
  149. #-(or sb-unicode ccl)
  150. (with-output-to-string (out)
  151. (loop for code = (read-byte socket)
  152. until (zerop code)
  153. do (write-char (code-char code) out)))
  154. #+ccl
  155. (let ((bytes (make-array 64
  156. :element-type '(unsigned-byte 8)
  157. :adjustable t
  158. :fill-pointer 0)))
  159. (loop for code = (read-byte socket)
  160. until (zerop code)
  161. do (vector-push-extend code bytes))
  162. (ccl:decode-string-from-octets bytes :external-format :utf-8))
  163. #+sb-unicode
  164. (let ((bytes (make-array 64
  165. :element-type '(unsigned-byte 8)
  166. :adjustable t
  167. :fill-pointer 0)))
  168. (loop for code = (read-byte socket)
  169. until (zerop code)
  170. do (vector-push-extend code bytes))
  171. (sb-ext:octets-to-string bytes)))
  172. (defmacro define-message-sender (name (&rest args) &rest clauses)
  173. (let ((socket-var (gensym))
  174. (body nil))
  175. (dolist (clause clauses)
  176. (let* ((type (first clause))
  177. (fn (intern (concatenate 'string (symbol-name '#:send-socket-value-)
  178. (symbol-name type)))))
  179. (push `(,fn ,socket-var ,@(rest clause)) body)))
  180. `(defun ,name (,socket-var ,@args)
  181. ,@(nreverse body))))
  182. (define-message-sender send-startup-message
  183. (database user &optional (command-line "") (backend-tty ""))
  184. (int32 296) ; Length
  185. (int32 #x00020000) ; Version 2.0
  186. (limstring database 64)
  187. (limstring user 32)
  188. (limstring command-line 64)
  189. (limstring "" 64) ; Unused
  190. (limstring backend-tty 64))
  191. (define-message-sender send-terminate-message ()
  192. (char-code #\X))
  193. (define-message-sender send-unencrypted-password-message (password)
  194. (int32 (+ 5 (length password)))
  195. (string password))
  196. (define-message-sender send-query-message (query)
  197. (char-code #\Q)
  198. (string query))
  199. (define-message-sender send-encrypted-password-message (crypted-password)
  200. (int32 (+ 5 (length crypted-password)))
  201. (string crypted-password))
  202. (define-message-sender send-cancel-request (pid key)
  203. (int32 16) ; Length
  204. (int32 80877102) ; Magic
  205. (int32 pid)
  206. (int32 key))
  207. (defun read-bytes (socket length)
  208. "Read a byte array of the given length from a stream."
  209. (declare (type stream socket)
  210. (type fixnum length)
  211. (optimize (speed 3) (safety 0)))
  212. (let ((result (make-array length :element-type '(unsigned-byte 8))))
  213. (read-sequence result socket)
  214. result))
  215. (defun read-socket-sequence (stream length &optional (allow-wide t))
  216. (declare (stream stream)
  217. (optimize (speed 3) (safety 0)))
  218. #-(or sb-unicode ccl)
  219. (let ((result (make-string length)))
  220. (dotimes (i length result)
  221. (declare (fixnum i))
  222. (setf (char result i) (code-char (read-byte stream)))))
  223. #+ccl
  224. (let ((bytes (make-array length :element-type '(unsigned-byte 8))))
  225. (declare (type (simple-array (unsigned-byte 8) (*)) bytes))
  226. (read-sequence bytes stream)
  227. (if allow-wide
  228. (ccl:decode-string-from-octets bytes :external-format :utf-8)
  229. (map 'string #'code-char bytes)))
  230. #+sb-unicode
  231. (let ((bytes (make-array length :element-type '(unsigned-byte 8))))
  232. (declare (type (simple-array (unsigned-byte 8) (*)) bytes))
  233. (read-sequence bytes stream)
  234. (if allow-wide
  235. (sb-ext:octets-to-string bytes)
  236. (map 'string #'code-char bytes))))
  237. ;;; Support for encrypted password transmission
  238. #-scl
  239. (eval-when (:compile-toplevel :load-toplevel :execute)
  240. (defvar *crypt-library-loaded* nil)
  241. (unless *crypt-library-loaded*
  242. (uffi:load-foreign-library
  243. (uffi:find-foreign-library "libcrypt"
  244. '(#+(or 64bit x86-64) "/usr/lib64/"
  245. "/usr/lib/" "/usr/local/lib/" "/lib/"))
  246. :supporting-libraries '("c"))
  247. (setq *crypt-library-loaded* t)))
  248. (in-package :postgresql-socket)
  249. (uffi:def-function ("crypt" crypt)
  250. ((key :cstring)
  251. (salt :cstring))
  252. :returning :cstring)
  253. (defun crypt-password (password salt)
  254. "Encrypt a password for transmission to a PostgreSQL server."
  255. (uffi:with-cstring (password-cstring password)
  256. (uffi:with-cstring (salt-cstring salt)
  257. (uffi:convert-from-cstring
  258. (crypt password-cstring salt-cstring)))))
  259. ;;;; Condition hierarchy
  260. (define-condition postgresql-condition (condition)
  261. ((connection :initarg :connection :reader postgresql-condition-connection)
  262. (message :initarg :message :reader postgresql-condition-message))
  263. (:report
  264. (lambda (c stream)
  265. (format stream "~@<~A occurred on connection ~A. ~:@_Reason: ~A~:@>"
  266. (type-of c)
  267. (postgresql-condition-connection c)
  268. (postgresql-condition-message c)))))
  269. (define-condition postgresql-error (error postgresql-condition)
  270. ())
  271. (define-condition postgresql-fatal-error (postgresql-error)
  272. ())
  273. (define-condition postgresql-login-error (postgresql-fatal-error)
  274. ())
  275. (define-condition postgresql-warning (warning postgresql-condition)
  276. ())
  277. (define-condition postgresql-notification (postgresql-condition)
  278. ()
  279. (:report
  280. (lambda (c stream)
  281. (format stream "~@<Asynchronous notification on connection ~A: ~:@_~A~:@>"
  282. (postgresql-condition-connection c)
  283. (postgresql-condition-message c)))))
  284. ;;; Structures
  285. (defstruct postgresql-connection
  286. host
  287. port
  288. database
  289. user
  290. password
  291. options
  292. tty
  293. socket
  294. pid
  295. key)
  296. (defstruct postgresql-cursor
  297. connection
  298. name
  299. fields)
  300. ;;; Socket stuff
  301. (defconstant +postgresql-server-default-port+ 5432
  302. "Default port of PostgreSQL server.")
  303. (defvar *postgresql-server-socket-timeout* 60
  304. "Timeout in seconds for reads from the PostgreSQL server.")
  305. #+(or cmu scl)
  306. (defun open-postgresql-socket (host port)
  307. (etypecase host
  308. (pathname
  309. ;; Directory to unix-domain socket
  310. (ext:connect-to-unix-socket
  311. (namestring
  312. (make-pathname :name ".s.PGSQL" :type (princ-to-string port)
  313. :defaults host))))
  314. (string
  315. (ext:connect-to-inet-socket host port))))
  316. #+sbcl
  317. (defun open-postgresql-socket (host port)
  318. (etypecase host
  319. (pathname
  320. ;; Directory to unix-domain socket
  321. (let ((sock (make-instance 'sb-bsd-sockets:local-socket
  322. :type :stream)))
  323. (sb-bsd-sockets:socket-connect
  324. sock
  325. (namestring
  326. (make-pathname :name ".s.PGSQL" :type (princ-to-string port)
  327. :defaults host)))
  328. sock))
  329. (string
  330. (let ((sock (make-instance 'sb-bsd-sockets:inet-socket
  331. :type :stream
  332. :protocol :tcp)))
  333. (sb-bsd-sockets:socket-connect
  334. sock
  335. (sb-bsd-sockets:host-ent-address
  336. (sb-bsd-sockets:get-host-by-name host))
  337. port)
  338. sock))))
  339. #+(or cmu scl)
  340. (defun open-postgresql-socket-stream (host port)
  341. (system:make-fd-stream
  342. (open-postgresql-socket host port)
  343. :input t :output t :element-type '(unsigned-byte 8)
  344. :buffering :none
  345. :timeout *postgresql-server-socket-timeout*))
  346. #+sbcl
  347. (defun open-postgresql-socket-stream (host port)
  348. (sb-bsd-sockets:socket-make-stream
  349. (open-postgresql-socket host port) :input t :output t
  350. :element-type '(unsigned-byte 8)))
  351. #+allegro
  352. (defun open-postgresql-socket-stream (host port)
  353. (etypecase host
  354. (pathname
  355. (let ((path (namestring
  356. (make-pathname :name ".s.PGSQL" :type (princ-to-string port)
  357. :defaults host))))
  358. (socket:make-socket :type :stream :address-family :file
  359. :connect :active
  360. :remote-filename path :local-filename path)))
  361. (string
  362. (socket:with-pending-connect
  363. (mp:with-timeout (*postgresql-server-socket-timeout* (error "connect failed"))
  364. (socket:make-socket :type :stream :address-family :internet
  365. :remote-port port :remote-host host
  366. :connect :active :nodelay t))))))
  367. #+openmcl
  368. (defun open-postgresql-socket-stream (host port)
  369. (etypecase host
  370. (pathname
  371. (let ((path (namestring
  372. (make-pathname :name ".s.PGSQL" :type (princ-to-string port)
  373. :defaults host))))
  374. (ccl:make-socket :type :stream :address-family :file
  375. :connect :active
  376. :remote-filename path :local-filename path)))
  377. (string
  378. (ccl:make-socket :type :stream :address-family :internet
  379. :remote-port port :remote-host host
  380. :connect :active :nodelay t))))
  381. #+lispworks
  382. (defun open-postgresql-socket-stream (host port)
  383. (etypecase host
  384. (pathname
  385. (error "File sockets not supported on Lispworks."))
  386. (string
  387. (comm:open-tcp-stream host port :direction :io :element-type '(unsigned-byte 8)
  388. :read-timeout *postgresql-server-socket-timeout*))
  389. ))
  390. #+clisp
  391. (defun open-postgresql-socket-stream (host port)
  392. (etypecase host
  393. (pathname
  394. (error "Not supported"))
  395. (string
  396. (socket:socket-connect
  397. port host
  398. :element-type '(unsigned-byte 8)
  399. :timeout *postgresql-server-socket-timeout*))))
  400. ;;; Interface Functions
  401. (defun open-postgresql-connection (&key (host (cmucl-compat:required-argument))
  402. (port +postgresql-server-default-port+)
  403. (database (cmucl-compat:required-argument))
  404. (user (cmucl-compat:required-argument))
  405. options tty password)
  406. "Open a connection to a PostgreSQL server with the given parameters.
  407. Note that host, database and user arguments must be supplied.
  408. If host is a pathname, it is assumed to name a directory containing
  409. the local unix-domain sockets of the server, with port selecting which
  410. of those sockets to open. If host is a string, it is assumed to be
  411. the name of the host running the PostgreSQL server. In that case a
  412. TCP connection to the given port on that host is opened in order to
  413. communicate with the server. In either case the port argument
  414. defaults to `+postgresql-server-default-port+'.
  415. Password is the clear-text password to be passed in the authentication
  416. phase to the server. Depending on the server set-up, it is either
  417. passed in the clear, or encrypted via crypt and a server-supplied
  418. salt. In that case the alien function specified by `*crypt-library*'
  419. and `*crypt-function-name*' is used for encryption.
  420. Note that all the arguments (including the clear-text password
  421. argument) are stored in the `postgresql-connection' structure, in
  422. order to facilitate automatic reconnection in case of communication
  423. troubles."
  424. (reopen-postgresql-connection
  425. (make-postgresql-connection :host host :port port
  426. :options (or options "") :tty (or tty "")
  427. :database database :user user
  428. :password (or password ""))))
  429. (defun byte-sequence-to-hex-string (sequence)
  430. (string-downcase (format nil "~{~2,'0X~}" (coerce sequence 'list))))
  431. (defun encrypt-password-md5 (password user salt)
  432. (let ((pass1 (byte-sequence-to-hex-string
  433. (md5::md5sum-string (concatenate 'string password user)))))
  434. (byte-sequence-to-hex-string
  435. (md5:md5sum-sequence (concatenate '(vector (unsigned-byte 8))
  436. (map '(vector (unsigned-byte 8)) #'char-code pass1)
  437. salt)))))
  438. (defun reopen-postgresql-connection (connection)
  439. "Reopen the given PostgreSQL connection. Closes any existing
  440. connection, if it is still open."
  441. (when (postgresql-connection-open-p connection)
  442. (close-postgresql-connection connection))
  443. (let ((socket (open-postgresql-socket-stream
  444. (postgresql-connection-host connection)
  445. (postgresql-connection-port connection))))
  446. (unwind-protect
  447. (progn
  448. (setf (postgresql-connection-socket connection) socket)
  449. (send-startup-message socket
  450. (postgresql-connection-database connection)
  451. (postgresql-connection-user connection)
  452. (postgresql-connection-options connection)
  453. (postgresql-connection-tty connection))
  454. (force-output socket)
  455. (loop
  456. (case (read-socket-value-int8 socket)
  457. (#.+authentication-message+
  458. (case (read-socket-value-int32 socket)
  459. (0 (return))
  460. ((1 2)
  461. (error 'postgresql-login-error
  462. :connection connection
  463. :message
  464. "Postmaster expects unsupported Kerberos authentication."))
  465. (3
  466. (send-unencrypted-password-message
  467. socket
  468. (postgresql-connection-password connection))
  469. (force-output socket))
  470. (4
  471. (let ((salt (read-socket-sequence socket 2 nil)))
  472. (send-encrypted-password-message
  473. socket
  474. (crypt-password
  475. (postgresql-connection-password connection) salt)))
  476. (force-output socket))
  477. (5
  478. (let ((salt (read-bytes socket 4)))
  479. (let ((pwd (encrypt-password-md5
  480. (postgresql-connection-password connection)
  481. (postgresql-connection-user connection)
  482. salt)))
  483. (send-encrypted-password-message
  484. socket
  485. (concatenate 'string "md5" pwd))))
  486. (force-output socket))
  487. (t
  488. (error 'postgresql-login-error
  489. :connection connection
  490. :message
  491. "Postmaster expects unknown authentication method."))))
  492. (#.+error-response-message+
  493. (let ((message (read-socket-value-string socket)))
  494. (error 'postgresql-login-error
  495. :connection connection :message message)))
  496. (t
  497. (error 'postgresql-login-error
  498. :connection connection
  499. :message
  500. "Received garbled message from Postmaster"))))
  501. ;; Start backend communication
  502. (force-output socket)
  503. (loop
  504. (case (read-socket-value-int8 socket)
  505. (#.+backend-key-message+
  506. (setf (postgresql-connection-pid connection)
  507. (read-socket-value-int32 socket)
  508. (postgresql-connection-key connection)
  509. (read-socket-value-int32 socket)))
  510. (#.+ready-for-query-message+
  511. (setq socket nil)
  512. (return connection))
  513. (#.+error-response-message+
  514. (let ((message (read-socket-value-string socket)))
  515. (error 'postgresql-login-error
  516. :connection connection
  517. :message message)))
  518. (#.+notice-response-message+
  519. (let ((message (read-socket-value-string socket)))
  520. (warn 'postgresql-warning :connection connection
  521. :message message)))
  522. (t
  523. (error 'postgresql-login-error
  524. :connection connection
  525. :message
  526. "Received garbled message from Postmaster")))))
  527. (when socket
  528. (close socket)))))
  529. (defun close-postgresql-connection (connection &optional abort)
  530. (unless abort
  531. (ignore-errors
  532. (send-terminate-message (postgresql-connection-socket connection))))
  533. (close (postgresql-connection-socket connection)))
  534. (defun postgresql-connection-open-p (connection)
  535. (let ((socket (postgresql-connection-socket connection)))
  536. (and socket (streamp socket) (open-stream-p socket))))
  537. (defun ensure-open-postgresql-connection (connection)
  538. (unless (postgresql-connection-open-p connection)
  539. (reopen-postgresql-connection connection)))
  540. (defun process-async-messages (connection)
  541. (assert (postgresql-connection-open-p connection))
  542. ;; Process any asnychronous messages
  543. (loop with socket = (postgresql-connection-socket connection)
  544. while (listen socket)
  545. do
  546. (case (read-socket-value-int8 socket)
  547. (#.+ready-for-query-message+)
  548. (#.+notice-response-message+
  549. (let ((message (read-socket-value-string socket)))
  550. (warn 'postgresql-warning :connection connection
  551. :message message)))
  552. (#.+notification-response-message+
  553. (let ((pid (read-socket-value-int32 socket))
  554. (message (read-socket-value-string socket)))
  555. (when (= pid (postgresql-connection-pid connection))
  556. (signal 'postgresql-notification :connection connection
  557. :message message))))
  558. (t
  559. (close-postgresql-connection connection)
  560. (error 'postgresql-fatal-error :connection connection
  561. :message "Received garbled message from backend")))))
  562. (defun start-query-execution (connection query)
  563. (ensure-open-postgresql-connection connection)
  564. (process-async-messages connection)
  565. (send-query-message (postgresql-connection-socket connection) query)
  566. (force-output (postgresql-connection-socket connection)))
  567. (defun wait-for-query-results (connection)
  568. (assert (postgresql-connection-open-p connection))
  569. (let ((socket (postgresql-connection-socket connection))
  570. (cursor-name nil)
  571. (error nil))
  572. (loop
  573. (case (read-socket-value-int8 socket)
  574. (#.+completed-response-message+
  575. (return (values :completed (read-socket-value-string socket))))
  576. (#.+cursor-response-message+
  577. (setq cursor-name (read-socket-value-string socket)))
  578. (#.+row-description-message+
  579. (let* ((count (read-socket-value-int16 socket))
  580. (fields
  581. (loop repeat count
  582. collect
  583. (list
  584. (read-socket-value-string socket)
  585. (read-socket-value-int32 socket)
  586. (read-socket-value-int16 socket)
  587. (read-socket-value-int32 socket)))))
  588. (return
  589. (values :cursor
  590. (make-postgresql-cursor :connection connection
  591. :name cursor-name
  592. :fields fields)))))
  593. (#.+copy-in-response-message+
  594. (return :copy-in))
  595. (#.+copy-out-response-message+
  596. (return :copy-out))
  597. (#.+ready-for-query-message+
  598. (when error
  599. (error error))
  600. (return nil))
  601. (#.+error-response-message+
  602. (let ((message (read-socket-value-string socket)))
  603. (setq error
  604. (make-condition 'postgresql-error
  605. :connection connection :message message))))
  606. (#.+notice-response-message+
  607. (let ((message (read-socket-value-string socket)))
  608. (unless (eq :ignore clsql-sys:*backend-warning-behavior*)
  609. (warn 'postgresql-warning
  610. :connection connection :message message))))
  611. (#.+notification-response-message+
  612. (let ((pid (read-socket-value-int32 socket))
  613. (message (read-socket-value-string socket)))
  614. (when (= pid (postgresql-connection-pid connection))
  615. (signal 'postgresql-notification :connection connection
  616. :message message))))
  617. (t
  618. (close-postgresql-connection connection)
  619. (error 'postgresql-fatal-error :connection connection
  620. :message "Received garbled message from backend"))))))
  621. (defun read-null-bit-vector (socket count)
  622. (let ((result (make-array count :element-type 'bit)))
  623. (dotimes (offset (ceiling count 8))
  624. (loop with byte = (read-byte socket)
  625. for index from (* offset 8) below (min count (* (1+ offset) 8))
  626. for weight downfrom 7
  627. do (setf (aref result index) (ldb (byte 1 weight) byte))))
  628. result))
  629. (defun read-field (socket type)
  630. (let ((length (- (read-socket-value-int32 socket) 4)))
  631. (case type
  632. ((:int32 :int64)
  633. (read-integer-from-socket socket length))
  634. (:double
  635. (read-double-from-socket socket length))
  636. (t
  637. (read-socket-sequence socket length)))))
  638. (uffi:def-constant +char-code-zero+ (char-code #\0))
  639. (uffi:def-constant +char-code-minus+ (char-code #\-))
  640. (uffi:def-constant +char-code-plus+ (char-code #\+))
  641. (uffi:def-constant +char-code-period+ (char-code #\.))
  642. (uffi:def-constant +char-code-lower-e+ (char-code #\e))
  643. (uffi:def-constant +char-code-upper-e+ (char-code #\E))
  644. (defun read-integer-from-socket (socket length)
  645. (declare (fixnum length))
  646. (if (zerop length)
  647. nil
  648. (let ((val 0)
  649. (first-char (read-byte socket))
  650. (minusp nil))
  651. (declare (fixnum first-char))
  652. (decf length) ;; read first char
  653. (cond
  654. ((= first-char +char-code-minus+)
  655. (setq minusp t))
  656. ((= first-char +char-code-plus+)
  657. ) ;; nothing to do
  658. (t
  659. (setq val (- first-char +char-code-zero+))))
  660. (dotimes (i length)
  661. (declare (fixnum i))
  662. (setq val (+
  663. (* 10 val)
  664. (- (read-byte socket) +char-code-zero+))))
  665. (if minusp
  666. (- val)
  667. val))))
  668. (defmacro ascii-digit (int)
  669. (let ((offset (gensym)))
  670. `(let ((,offset (- ,int +char-code-zero+)))
  671. (declare (fixnum ,int ,offset))
  672. (if (and (>= ,offset 0)
  673. (< ,offset 10))
  674. ,offset
  675. nil))))
  676. (defun read-double-from-socket (socket length)
  677. (declare (fixnum length))
  678. (let ((before-decimal 0)
  679. (after-decimal 0)
  680. (decimal-count 0)
  681. (exponent 0)
  682. (decimalp nil)
  683. (minusp nil)
  684. (result nil)
  685. (char (read-byte socket)))
  686. (declare (fixnum char exponent decimal-count))
  687. (decf length) ;; already read first character
  688. (cond
  689. ((= char +char-code-minus+)
  690. (setq minusp t))
  691. ((= char +char-code-plus+)
  692. )
  693. ((= char +char-code-period+)
  694. (setq decimalp t))
  695. (t
  696. (setq before-decimal (ascii-digit char))
  697. (unless before-decimal
  698. (error "Unexpected value"))))
  699. (block loop
  700. (dotimes (i length)
  701. (setq char (read-byte socket))
  702. ;; (format t "~&len:~D, i:~D, char:~D, minusp:~A, decimalp:~A" length i char minusp decimalp)
  703. (let ((weight (ascii-digit char)))
  704. (cond
  705. ((and weight (not decimalp)) ;; before decimal point
  706. (setq before-decimal (+ weight (* 10 before-decimal))))
  707. ((and weight decimalp) ;; after decimal point
  708. (setq after-decimal (+ weight (* 10 after-decimal)))
  709. (incf decimal-count))
  710. ((and (= char +char-code-period+))
  711. (setq decimalp t))
  712. ((or (= char +char-code-lower-e+) ;; E is for exponent
  713. (= char +char-code-upper-e+))
  714. (setq exponent (read-integer-from-socket socket (- length i 1)))
  715. (setq exponent (or exponent 0))
  716. (return-from loop))
  717. (t
  718. (break "Unexpected value"))
  719. )
  720. )))
  721. (setq result (* (+ (coerce before-decimal 'double-float)
  722. (* after-decimal
  723. (expt 10 (- decimal-count))))
  724. (expt 10 exponent)))
  725. (if minusp
  726. (- result)
  727. result)))
  728. #+ignore
  729. (defun read-double-from-socket (socket length)
  730. (let ((result (make-string length)))
  731. (read-socket-sequence result socket)
  732. (let ((*read-default-float-format* 'double-float))
  733. (read-from-string result))))
  734. (defun read-cursor-row (cursor types)
  735. (let* ((connection (postgresql-cursor-connection cursor))
  736. (socket (postgresql-connection-socket connection))
  737. (fields (postgresql-cursor-fields cursor)))
  738. (assert (postgresql-connection-open-p connection))
  739. (loop
  740. (let ((code (read-socket-value-int8 socket)))
  741. (case code
  742. (#.+ascii-row-message+
  743. (return
  744. (loop with count = (length fields)
  745. with null-vector = (read-null-bit-vector socket count)
  746. repeat count
  747. for null-bit across null-vector
  748. for i from 0
  749. for null-p = (zerop null-bit)
  750. if null-p
  751. collect nil
  752. else
  753. collect
  754. (read-field socket (nth i types)))))
  755. (#.+binary-row-message+
  756. (error "NYI"))
  757. (#.+completed-response-message+
  758. (return (values nil (read-socket-value-string socket))))
  759. (#.+error-response-message+
  760. (let ((message (read-socket-value-string socket)))
  761. (error 'postgresql-error
  762. :connection connection :message message)))
  763. (#.+notice-response-message+
  764. (let ((message (read-socket-value-string socket)))
  765. (warn 'postgresql-warning
  766. :connection connection :message message)))
  767. (#.+notification-response-message+
  768. (let ((pid (read-socket-value-int32 socket))
  769. (message (read-socket-value-string socket)))
  770. (when (= pid (postgresql-connection-pid connection))
  771. (signal 'postgresql-notification :connection connection
  772. :message message))))
  773. (t
  774. (close-postgresql-connection connection)
  775. (error 'postgresql-fatal-error :connection connection
  776. :message "Received garbled message from backend")))))))
  777. (defun map-into-indexed (result-seq func seq)
  778. (dotimes (i (length seq))
  779. (declare (fixnum i))
  780. (setf (elt result-seq i)
  781. (funcall func (elt seq i) i)))
  782. result-seq)
  783. (defun copy-cursor-row (cursor sequence types)
  784. (let* ((connection (postgresql-cursor-connection cursor))
  785. (socket (postgresql-connection-socket connection))
  786. (fields (postgresql-cursor-fields cursor)))
  787. (assert (= (length fields) (length sequence)))
  788. (loop
  789. (let ((code (read-socket-value-int8 socket)))
  790. (case code
  791. (#.+ascii-row-message+
  792. (return
  793. #+ignore
  794. (let* ((count (length sequence))
  795. (null-vector (read-null-bit-vector socket count)))
  796. (dotimes (i count)
  797. (declare (fixnum i))
  798. (if (zerop (elt null-vector i))
  799. (setf (elt sequence i) nil)
  800. (let ((value (read-field socket (nth i types))))
  801. (setf (elt sequence i) value)))))
  802. (map-into-indexed
  803. sequence
  804. #'(lambda (null-bit i)
  805. (if (zerop null-bit)
  806. nil
  807. (read-field socket (nth i types))))
  808. (read-null-bit-vector socket (length sequence)))))
  809. (#.+binary-row-message+
  810. (error "NYI"))
  811. (#.+completed-response-message+
  812. (return (values nil (read-socket-value-string socket))))
  813. (#.+error-response-message+
  814. (let ((message (read-socket-value-string socket)))
  815. (error 'postgresql-error
  816. :connection connection :message message)))
  817. (#.+notice-response-message+
  818. (let ((message (read-socket-value-string socket)))
  819. (warn 'postgresql-warning
  820. :connection connection :message message)))
  821. (#.+notification-response-message+
  822. (let ((pid (read-socket-value-int32 socket))
  823. (message (read-socket-value-string socket)))
  824. (when (= pid (postgresql-connection-pid connection))
  825. (signal 'postgresql-notification :connection connection
  826. :message message))))
  827. (t
  828. (close-postgresql-connection connection)
  829. (error 'postgresql-fatal-error :connection connection
  830. :message "Received garbled message from backend")))))))
  831. (defun skip-cursor-row (cursor)
  832. (let* ((connection (postgresql-cursor-connection cursor))
  833. (socket (postgresql-connection-socket connection))
  834. (fields (postgresql-cursor-fields cursor)))
  835. (loop
  836. (let ((code (read-socket-value-int8 socket)))
  837. (case code
  838. (#.+ascii-row-message+
  839. (loop for null-bit across
  840. (read-null-bit-vector socket (length fields))
  841. do
  842. (unless (zerop null-bit)
  843. (let* ((length (read-socket-value-int32 socket)))
  844. (loop repeat (- length 4) do (read-byte socket)))))
  845. (return t))
  846. (#.+binary-row-message+
  847. (error "NYI"))
  848. (#.+completed-response-message+
  849. (return (values nil (read-socket-value-string socket))))
  850. (#.+error-response-message+
  851. (let ((message (read-socket-value-string socket)))
  852. (error 'postgresql-error
  853. :connection connection :message message)))
  854. (#.+notice-response-message+
  855. (let ((message (read-socket-value-string socket)))
  856. (warn 'postgresql-warning
  857. :connection connection :message message)))
  858. (#.+notification-response-message+
  859. (let ((pid (read-socket-value-int32 socket))
  860. (message (read-socket-value-string socket)))
  861. (when (= pid (postgresql-connection-pid connection))
  862. (signal 'postgresql-notification :connection connection
  863. :message message))))
  864. (t
  865. (close-postgresql-connection connection)
  866. (error 'postgresql-fatal-error :connection connection
  867. :message "Received garbled message from backend")))))))
  868. (defun run-query (connection query &optional (result-types nil))
  869. (start-query-execution connection query)
  870. (multiple-value-bind (status cursor)
  871. (wait-for-query-results connection)
  872. (assert (eq status :cursor))
  873. (loop for row = (read-cursor-row cursor result-types)
  874. while row
  875. collect row
  876. finally
  877. (wait-for-query-results connection))))
  878. #+scl
  879. (declaim (ext:maybe-inline read-byte write-byte))