2.5. Accessing Large Objects from Libpq

Example 2-1 is a sample program which shows how the large object interface in libpq can be used. Parts of the program are commented out but are left in the source for the reader's benefit. This program can be found in src/test/examples/testlo.c in the source distribution. Frontend applications which use the large object interface in libpq should link with the libpq library.

Example 2-1. Large Objects with Libpq Example Program

;;;--------------------------------------------------------------
;;;
;;; testlo.scm
;;;   test using large objects with libpq
;;;
;;; Copyright (c) 2004, Zbyszek Jurkiewicz
;;;
;;;--------------------------------------------------------------

(require (lib "libpq-fe.scm" "libpq"))

(define (pickout conn lobjId start len)
  (let ((lobj-fd (lo-open conn lobjId INV-READ)))
    (when (< lobj_fd 0)
      (fprintf (current-error-port) "can't open large object ~a\n"
               lobjId))
    (lo_lseek conn lobj-fd start SEEK-SET)
    (let ((buf (make-string (+ len 1))))
      (let loop ((nread 0))
        (when (> (- len nread) 0)
          (let ((nbytes (lo-read conn lobj-fd buf (- len nread))))
            (string-set! buf nbytes #\space)  ;???
            (fprintf (current-error-port) ">>> ~a" buf)
            (loop (+ nread nbytes))))))
    (fprintf (current-error-port) "\n")
    (lo-close conn lobj-fd)))

(define (overwrite conn lobjId start len)
  (let ((lobj-fd (lo-open conn lobjId INV-READ)))
    (when (< lobj-fd 0)
      (fprintf (current-error-port) "can't open large object ~a\n"
               lobjId))
    (lo-lseek conn lobj_fd start SEEK-SET)
    (let ((buf (make-string (+ len 1) #\X)))
      (string-set! buf len #\space)  ;???
      (let loop ((nwritten 0))
        (when (> (- len nwritten) 0)
          (let ((nbytes
                 ;;!!! Zmienic (GC) 
                 (lo_write conn lobj-fd (substring buf nwritten)
                           (- len nwritten))))
            (loop (+ nwritten nbytes))))))
    (fprintf (current-error-port) "\n")
    (lo-close conn lobj-fd)))

(define (exit-nicely conn)
  (PQ-finish conn)
  (exit 1))

(define (main argc argv)
  (unless (= argc 4)
    (fprintf (current-error-port)
             "Usage: ~a database_name in_filename out_filename\n"
             (vector-ref argv 0))
    (exit 1))
  (let ((database (vector-ref argv 1))
        (in-filename (vector-ref argv 2))
        (out-filename (vector-ref argv 3)))
    ;; Set up the connection
    (let ((conn (PQ-setdb #f #f #f #f database)))
      ;; Check to see that the backend connection was successfully made
      (when (equal (PQ-status conn) CONNECTION-BAD)
        (fprintf (current-error-port) "Connection to database '~a' failed.\n"
                 database)
        (fprintf (current-error-port) "~a" (PQ-error-message conn))
        (exit-nicely conn))
      (PQ-clear (PQ-exec conn "begin"))
      (printf "importing file ~a\n" in-filename)
      (let ((lobj-Oid (lo-import conn in-filename)))
        ;;(printf "as large object ~a.\n" lobj-Oid)
        ;;(printf "picking out bytes 1000-2000 of the large object\n")
        ;;(pickout conn lobj-Oid 1000 1000)
        ;;(printf "overwriting bytes 1000-2000 of the large object with X's\n")
        ;;(overwrite conn lobjOid 1000 1000)
        (printf "exporting large object to file ~a\n" out-filename)
        (lo-export conn lobj-Oid out-filename))
      (PQ-clear (PQ-exec conn "end"))
      (PQ-finish conn)
      (exit 0))))