;;;;
;;;; Date Started: Feb 2002
;;;;
-;;;; $Id: postgresql-socket-api.cl,v 1.4 2002/03/25 23:30:49 kevin Exp $
+;;;; $Id: postgresql-socket-api.cl,v 1.6 2002/03/26 14:12:12 kevin Exp $
;;;;
;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
;;;; and Copyright (c) 1999-2001 by Pierre R. Mai
(defun read-socket-sequence (string stream)
"KMR -- Added to support reading from binary stream into a string"
- (declare (optimize (speed 3) (safety 0)))
+ (declare (optimize (speed 3) (safety 0))
+ (string string))
(dotimes (i (length string))
(declare (fixnum i))
(setf (char string i) (code-char (read-byte stream))))
do (setf (aref result index) (ldb (byte 1 weight) byte))))
result))
+
(defun read-field (socket type)
- (let* ((length (read-socket-value 'int32 socket))
- (result (make-string (- length 4))))
- (read-socket-sequence result socket)
+ (let* ((length (- (read-socket-value 'int32 socket) 4)))
(case type
(:int
- (parse-integer result))
+ (read-integer-from-socket socket length))
(:double
- (let ((*read-default-float-format* 'double-float))
- (read-from-string result)))
+ (read-double-from-socket socket length))
(t
- result))))
+ (let ((result (make-string length)))
+ (read-socket-sequence result socket)
+ result)))))
+
+(uffi:def-constant +char-code-zero+ (char-code #\0))
+(uffi:def-constant +char-code-minus+ (char-code #\-))
+(uffi:def-constant +char-code-plus+ (char-code #\+))
+(uffi:def-constant +char-code-period+ (char-code #\.))
+
+(defun read-integer-from-socket (socket length)
+ (let ((val 0)
+ (first-char (read-byte socket))
+ (minusp nil))
+ (declare (fixnum first-char))
+ (if (eql first-char +char-code-minus+)
+ (setq minusp t)
+ (setq val (- first-char +char-code-zero+)))
+ (dotimes (i (1- length))
+ (declare (fixnum i))
+ (setq val (+
+ (* 10 val)
+ (- (read-byte socket) +char-code-zero+))))
+ (if minusp
+ (- 0 val)
+ val)))
+
+(defmacro ascii-digit (int)
+ (let ((offset (gensym)))
+ `(let ((,offset (- ,int +char-code-zero+)))
+ (declare (fixnum ,int ,offset))
+ (if (and (plusp ,offset)
+ (< ,offset 10))
+ ,offset
+ nil))))
+
+#+ignore
+(defun read-double-from-socket (socket length)
+ (let ((before-decimal 0)
+ (after-decimal 0)
+ (decimal-count 0)
+ (exponent 0)
+ (char (read-byte socket))
+ (decimalp nil)
+ (minusp nil))
+ (declare (fixnum first-char))
+ (cond
+ ((eql char +char-code-minus+)
+ (setq minusp t)
+ (setq char (read-byte socket))
+ (decf length))
+ ((eql char +char-code-plus+)
+ (setq char (read-byte socket))
+ (decf length)))
+
+ (dotimes (i (1- length))
+ (let ((weight (ascii-digit char)))
+ (cond
+ ((and weight (not decimalp)) ;; before decimal point
+ (setq before-decimal (+ weight (* 10 before-decimal))))
+ ((and weight decimalp) ;; after decimal point
+ (setq after-decimal (+ weight (* 10 after-decimal)))
+ (incf decimal-count))
+ ((and (eql char +char-code-period+) decimalp)
+ (setq decimalp t))
+ ((or (eql char +char-code-e+) ;; E is for exponent
+ (eql char +char-code-upper-e+))
+ (multiple-value-bind (num idx)
+ (parse-integer string :start (1+ index) :end end
+ :radix radix :junk-allowed junk-allowed)
+ (setq exponent (or num 0)
+ index idx)
+ (when (= index end) (return nil))))
+ )
+ (setq char (read-byte socket))))
+
+
+
+
+ ))
+
+
+(defun read-double-from-socket (socket length)
+ (let ((result (make-string length)))
+ (read-socket-sequence result socket)
+ (let ((*read-default-float-format* 'double-float))
+ (read-from-string result))))
-(defun read-cursor-row (cursor field-types)
+(defun read-cursor-row (cursor types)
(let* ((connection (postgresql-cursor-connection cursor))
(socket (postgresql-connection-socket connection))
(fields (postgresql-cursor-fields cursor)))
collect nil
else
collect
- (read-field socket (nth i field-types)))))
+ (read-field socket (nth i types)))))
(#.+binary-row-message+
(error "NYI"))
(#.+completed-response-message+
(funcall func (elt seq i) i)))
result-seq)
-(defun copy-cursor-row (cursor sequence field-types)
+(defun copy-cursor-row (cursor sequence types)
(let* ((connection (postgresql-cursor-connection cursor))
(socket (postgresql-connection-socket connection))
(fields (postgresql-cursor-fields cursor)))
(declare (fixnum i))
(if (zerop (elt null-vector i))
(setf (elt sequence i) nil)
- (let ((value (read-field socket (nth i field-types))))
+ (let ((value (read-field socket (nth i types))))
(setf (elt sequence i) value)))))
(map-into-indexed
sequence
#'(lambda (null-bit i)
(if (zerop null-bit)
nil
- (read-field socket (nth i field-types))))
+ (read-field socket (nth i types))))
(read-null-bit-vector socket (length sequence)))))
(#.+binary-row-message+
(error "NYI"))
(error 'postgresql-fatal-error :connection connection
:message "Received garbled message from backend")))))))
-(defun run-query (connection query &optional (field-types nil))
+(defun run-query (connection query &optional (types nil))
(start-query-execution connection query)
(multiple-value-bind (status cursor)
(wait-for-query-results connection)
(assert (eq status :cursor))
- (loop for row = (read-cursor-row cursor field-types)
+ (loop for row = (read-cursor-row cursor types)
while row
collect row
finally