diff --git a/Database/PostgreSQL/LibPQ.hsc b/Database/PostgreSQL/LibPQ.hsc
--- a/Database/PostgreSQL/LibPQ.hsc
+++ b/Database/PostgreSQL/LibPQ.hsc
@@ -14,8 +14,8 @@
 -- server and to receive the results of these queries.
 --
 -- This is intended to be a very low-level interface to libpq.  It
--- provides memory management and a somewhat more consistent interface 
--- to error conditions.  Application code should typically use a 
+-- provides memory management and a somewhat more consistent interface
+-- to error conditions.  Application code should typically use a
 -- higher-level PostgreSQL binding.
 --
 -- This interface is not safe,  because libpq unfortunately conflates
@@ -177,6 +177,8 @@
     , trace
     , untrace
 
+    -- * Large Objects
+    -- $largeobjects
     , LoFd(..)
     , loCreat
     , loCreate
@@ -2041,6 +2043,8 @@
 --     where
 --       finalizer = touchForeignPtr fp
 
+-- $largeobjects
+
 -- | LoFd is a Large Object (pseudo) File Descriptor.  It is understood by
 -- libpq but not by operating system calls.
 
@@ -2049,41 +2053,91 @@
 loMode :: IOMode -> CInt
 loMode mode = case mode of
                 ReadMode      -> (#const INV_READ)
-                _             -> (#const INV_READ) .|. (#const INV_WRITE)
+                WriteMode     -> (#const INV_WRITE)
+                ReadWriteMode -> (#const INV_READ) .|. (#const INV_WRITE)
+                AppendMode    -> (#const INV_WRITE)
 
 toMaybeOid :: Oid -> Maybe Oid
 toMaybeOid oid | oid == invalidOid = Nothing
                | otherwise         = Just oid
 {-# INLINE toMaybeOid #-}
 
+nonnegInt :: CInt -> Maybe Int
+nonnegInt x = if x < 0 then Nothing else Just (fromIntegral x)
+{-# INLINE nonnegInt #-}
+
+negError  :: CInt -> Maybe ()
+negError x = if x < 0 then Nothing else Just ()
+{-# INLINE negError #-}
+
+-- | Creates a new large object,  returns the Object ID of the newly created
+-- object.
+
 loCreat :: Connection -> IO (Maybe Oid)
 loCreat connection
     = withConn connection $ \c -> do
         toMaybeOid `fmap` c_lo_creat c (loMode ReadMode)
 
+-- | Creates a new large object with a particular Object ID.  Returns
+-- 'Nothing' if the requested Object ID is already in use by some other
+-- large object or other failure.  If 'invalidOid' is used as a parameter,
+-- then 'loCreate' will assign an unused 'Oid'.
+
 loCreate :: Connection -> Oid -> IO (Maybe Oid)
 loCreate connection oid
     = withConn connection $ \c -> do
         toMaybeOid `fmap` c_lo_create c oid
 
+-- | Imports an operating system file as a large object.  Note that the
+-- file is read by the client interface library, not by the server; so it
+-- must exist in the client file system and be readable by the client
+-- application.
+
 loImport :: Connection -> FilePath -> IO (Maybe Oid)
 loImport connection filepath
     = withConn connection $ \c -> do
         withCString filepath $ \f -> do
           toMaybeOid `fmap` c_lo_import c f
 
+-- | Imports an operating system file as a large object with the given
+-- Object ID.  Combines the behavior of 'loImport' and 'loCreate'
+
 loImportWithOid :: Connection -> FilePath -> Oid -> IO (Maybe Oid)
 loImportWithOid connection filepath oid
     = withConn connection $ \c -> do
         withCString filepath $ \f -> do
           toMaybeOid `fmap` c_lo_import_with_oid c f oid
 
-loExport :: Connection -> Oid -> FilePath -> IO CInt
+-- | Exports a large object into a operating system file.  Note that
+-- the file is written by the client interface library, not the server.
+-- Returns 'Just ()' on success,  'Nothing' on failure.
+
+loExport :: Connection -> Oid -> FilePath -> IO (Maybe ())
 loExport connection oid filepath
     = withConn connection $ \c -> do
         withCString filepath $ \f -> do
-          c_lo_export c oid f
+          negError `fmap` c_lo_export c oid f
 
+-- | Opens an existing large object for reading or writing.  The Oid specifies
+-- the large object to open.  A large object cannot be opened before it is
+-- created.  A large object descriptor is returned for later use in 'loRead',
+-- 'loWrite', 'loSeek', 'loTell', and 'loClose'.   The descriptor is only valid
+-- for the duration of the current transation.   On failure,  'Nothing' is
+-- returned.
+--
+-- The server currently does not distinguish between 'WriteMode' and
+-- 'ReadWriteMode';  write-only modes are not enforced.  However there
+-- is a significant difference between 'ReadMode' and the other modes:
+-- with 'ReadMode' you cannot write on the descriptor,  and the data read
+-- from it will reflect the contents of the large object at the time of
+-- the transaction snapshot that was active when 'loOpen' was executed,
+-- regardless of later writes by this or other transactions.   Reading from
+-- a descriptor opened in 'WriteMode', 'ReadWriteMode', or 'AppendMode'
+-- returns data that reflects all writes of other committed transactions
+-- as well as the writes of the current transaction.   This is similar to
+-- the behavior of @REPEATABLE READ@ versus @READ COMMITTED@ transaction
+-- modes for ordinary SQL @SELECT@ commands.
+
 loOpen :: Connection -> Oid -> IOMode -> IO (Maybe LoFd)
 loOpen connection oid mode
     = withConn connection $ \c -> do
@@ -2095,9 +2149,10 @@
                 -- The Large Object API does not directly support AppendMode,
                 -- so we emulate it.
 
-                -- FIXME:  review this emulation as it and/or the error handling is
-                --         likely to be slightly wrong.  Start by reading the source
-                --         of lo_open, lo_lseek, and lo_close.
+                -- FIXME:  review this emulation as it and/or the error
+                --         handling is likely to be slightly wrong.  Start by
+                --         reading the source of lo_open, lo_lseek, and
+                --         lo_close.
                 err <- c_lo_lseek c fd 0 (#const SEEK_END)
                 case err of
                   -1 -> do
@@ -2110,56 +2165,83 @@
                           return Nothing
                   _  -> return (Just (LoFd fd))
 
+-- | @loWrite conn fd buf@ writes the bytestring @buf@ to the large object
+-- descriptor @fd@.  The number of bytes actually written is returned.
+-- In the event of an error, 'Nothing' is returned.
 
-loWrite :: Connection -> LoFd -> B.ByteString -> IO Int
+loWrite :: Connection -> LoFd -> B.ByteString -> IO (Maybe Int)
 loWrite connection (LoFd fd) bytes
     = withConn connection $ \c -> do
         B.unsafeUseAsCStringLen bytes $ \(byteptr,len) -> do
-          nbytes_written <- c_lo_write c fd byteptr (fromIntegral len)
-          return (fromIntegral nbytes_written)
+          nonnegInt `fmap` c_lo_write c fd byteptr (fromIntegral len)
 
-loRead :: Connection -> LoFd -> Int -> IO B.ByteString
-loRead connection (LoFd fd) maxlen
+-- | @loRead conn fd len@ reads up to @len@ bytes from the large object
+-- descriptor @fd@.  In the event of an error,  'Nothing' is returned.
+
+loRead :: Connection -> LoFd -> Int -> IO (Maybe B.ByteString)
+loRead connection (LoFd !fd) !maxlen
     = withConn connection $ \c -> do
-        allocaBytes maxlen $ \(buf :: CString) -> do
-          len <- c_lo_read c fd buf (fromIntegral maxlen)
-          B.packCStringLen (buf,fromIntegral len)
+        buf <- mallocBytes maxlen
+        len_ <- c_lo_read c fd buf (fromIntegral maxlen)
+        let len = fromIntegral len_
+        if len < 0
+          then do
+                  free buf
+                  return Nothing
+          else do
+                  bufre <- reallocBytes buf len
+                  buffp <- newForeignPtr finalizerFree bufre
+                  return (Just (B.fromForeignPtr buffp 0 len))
 
-loSeek :: Connection -> LoFd -> SeekMode -> Int -> IO Bool
+-- | Changes the current read or write location associated with
+-- a large object descriptor.    The return value is the new location
+-- pointer,  or 'Nothing' on error.
+
+loSeek :: Connection -> LoFd -> SeekMode -> Int -> IO (Maybe Int)
 loSeek connection (LoFd fd) seekmode delta
     = withConn connection $ \c -> do
         let d = fromIntegral delta
-        err <- c_lo_lseek c fd d $ case seekmode of
+        pos <- c_lo_lseek c fd d $ case seekmode of
                                      AbsoluteSeek -> #const SEEK_SET
                                      RelativeSeek -> #const SEEK_CUR
                                      SeekFromEnd  -> #const SEEK_END
-        return (err >= 0)
+        return (nonnegInt pos)
 
+-- | Obtains the current read or write location of a large object descriptor.
+
 loTell :: Connection -> LoFd -> IO (Maybe Int)
 loTell connection (LoFd fd)
     = withConn connection $ \c -> do
-        pos <- c_lo_tell c fd
-        if pos >= 0
-          then return (Just (fromIntegral pos))
-          else return Nothing
+        nonnegInt `fmap` c_lo_tell c fd
 
-loTruncate :: Connection -> LoFd -> Int -> IO Bool
+-- | Truncates a large object to a given length.  If the length is greater
+-- than the current large object,  then the large object is extended with
+-- null bytes.  ('\x00')
+--
+-- The file offest is not changed.
+--
+-- 'loTruncate' is new as of PostgreSQL 8.3; if this function is run against
+-- an older server version, it will fail and return 'Nothing'
+
+loTruncate :: Connection -> LoFd -> Int -> IO (Maybe ())
 loTruncate connection (LoFd fd) size
     = withConn connection $ \c -> do
-        err <- c_lo_truncate c fd (fromIntegral size)
-        return (err >= 0)
+        negError `fmap` c_lo_truncate c fd (fromIntegral size)
 
-loClose :: Connection -> LoFd -> IO Bool
+-- | Closes a large object descriptor.  Any large object descriptors that
+-- remain open at the end of a transaction will be closed automatically.
+
+loClose :: Connection -> LoFd -> IO (Maybe ())
 loClose connection (LoFd fd)
     = withConn connection $ \c -> do
-        err <- c_lo_close c fd
-        return (err >= 0)
+        negError `fmap` c_lo_close c fd
 
-loUnlink :: Connection -> Oid -> IO Bool
+-- | Removes a large object from the database.
+
+loUnlink :: Connection -> Oid -> IO (Maybe ())
 loUnlink connection oid
     = withConn connection $ \c -> do
-        err <- c_lo_unlink c oid
-        return (err >= 0)
+        negError `fmap` c_lo_unlink c oid
 
 foreign import ccall        "libpq-fe.h PQconnectdb"
     c_PQconnectdb :: CString ->IO (Ptr PGconn)
@@ -2453,7 +2535,7 @@
     c_lo_write :: Ptr PGconn -> CFd -> CString -> CSize -> IO CInt
 
 foreign import ccall        "libpq-fs.h lo_read"
-    c_lo_read :: Ptr PGconn -> CFd -> CString -> CSize -> IO CInt
+    c_lo_read :: Ptr PGconn -> CFd -> Ptr Word8 -> CSize -> IO CInt
 
 foreign import ccall        "libpq-fs.h lo_lseek"
     c_lo_lseek :: Ptr PGconn -> CFd -> CInt -> CInt -> IO CInt
diff --git a/postgresql-libpq.cabal b/postgresql-libpq.cabal
--- a/postgresql-libpq.cabal
+++ b/postgresql-libpq.cabal
@@ -1,6 +1,6 @@
 Name:                postgresql-libpq
-Version:             0.5
-Synopsis:            libpq binding for Haskell
+Version:             0.6
+Synopsis:            low-level binding to libpq
 
 Description:         This is a binding to libpq: the C application
                      programmer's interface to PostgreSQL. libpq is a
@@ -9,12 +9,13 @@
                      backend server and to receive the results of
                      these queries.
 
-Homepage:            http://github.com/lpsmith/haskell-libpq
+Homepage:            http://github.com/lpsmith/postgresql-libpq
 License:             BSD3
 License-file:        LICENSE
 Author:              Grant Monroe, Leon P Smith
-Maintainer:          leon@melding-monads.com
--- Copyright:
+Maintainer:          Leon P Smith <leon@melding-monads.com>
+Copyright:           (c) 2010 Grant Monroe
+                     (c) 2011 Leon P Smith
 Category:            Database
 Build-type:          Custom
 -- Extra-source-files:
@@ -33,10 +34,9 @@
 
 source-repository head
   type:     git
-  location: http://github.com/lpsmith/haskell-libpq
+  location: http://github.com/lpsmith/postgresql-libpq
 
 source-repository this
   type:     git
-  location: http://github.com/lpsmith/haskell-libpq
-  tag:      v0.5
-
+  location: http://github.com/lpsmith/postgresql-libpq
+  tag:      v0.6
