PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

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

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