packages feed

direct-sqlite 2.3.14 → 2.3.15

raw patch · 7 files changed

+467/−3 lines, 7 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Database.SQLite3: BackupDone :: BackupStepResult
+ Database.SQLite3: BackupOK :: BackupStepResult
+ Database.SQLite3: backupFinish :: Backup -> IO (())
+ Database.SQLite3: backupInit :: Database -> Text -> Database -> Text -> IO Backup
+ Database.SQLite3: backupPagecount :: Backup -> IO Int
+ Database.SQLite3: backupRemaining :: Backup -> IO Int
+ Database.SQLite3: backupStep :: Backup -> Int -> IO BackupStepResult
+ Database.SQLite3: bindZeroBlob :: Statement -> ParamIndex -> Int -> IO ()
+ Database.SQLite3: blobBytes :: Blob -> IO Int
+ Database.SQLite3: blobClose :: Blob -> IO ()
+ Database.SQLite3: blobOpen :: Database -> Text -> Text -> Text -> Int64 -> Bool -> IO Blob
+ Database.SQLite3: blobRead :: Blob -> Int -> Int -> IO ByteString
+ Database.SQLite3: blobReadBuf :: Blob -> Ptr a -> Int -> Int -> IO ()
+ Database.SQLite3: blobReopen :: Blob -> Int64 -> IO ()
+ Database.SQLite3: blobWrite :: Blob -> ByteString -> Int -> IO ()
+ Database.SQLite3: data Backup
+ Database.SQLite3: data BackupStepResult
+ Database.SQLite3: data Blob
+ Database.SQLite3: funcResultZeroBlob :: FuncContext -> Int -> IO ()
+ Database.SQLite3: getFuncContextDatabase :: FuncContext -> IO Database
+ Database.SQLite3.Bindings: c_sqlite3_backup_finish :: Ptr CBackup -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_backup_init :: Ptr CDatabase -> CString -> Ptr CDatabase -> CString -> IO (Ptr CBackup)
+ Database.SQLite3.Bindings: c_sqlite3_backup_pagecount :: Ptr CBackup -> IO CInt
+ Database.SQLite3.Bindings: c_sqlite3_backup_remaining :: Ptr CBackup -> IO CInt
+ Database.SQLite3.Bindings: c_sqlite3_backup_step :: Ptr CBackup -> CInt -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_bind_zeroblob :: Ptr CStatement -> CParamIndex -> CInt -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_blob_bytes :: Ptr CBlob -> IO CInt
+ Database.SQLite3.Bindings: c_sqlite3_blob_close :: Ptr CBlob -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_blob_open :: Ptr CDatabase -> CString -> CString -> CString -> Int64 -> CInt -> Ptr (Ptr CBlob) -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_blob_read :: Ptr CBlob -> Ptr a -> CInt -> CInt -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_blob_reopen :: Ptr CBlob -> Int64 -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_blob_write :: Ptr CBlob -> Ptr a -> CInt -> CInt -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_enable_shared_cache :: CInt -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_errcode :: Ptr CDatabase -> IO CError
+ Database.SQLite3.Bindings: c_sqlite3_wal_hook :: Ptr CDatabase -> FunPtr CWalHook -> Ptr a -> IO (Ptr ())
+ Database.SQLite3.Bindings: mkCWalHook :: CWalHook -> IO (FunPtr CWalHook)
+ Database.SQLite3.Bindings: type CWalHook = Ptr () -> Ptr CDatabase -> CString -> CInt -> IO CError
+ Database.SQLite3.Bindings.Types: data CBackup
+ Database.SQLite3.Bindings.Types: data CBlob
+ Database.SQLite3.Direct: Backup :: Database -> (Ptr CBackup) -> Backup
+ Database.SQLite3.Direct: BackupDone :: BackupStepResult
+ Database.SQLite3.Direct: BackupOK :: BackupStepResult
+ Database.SQLite3.Direct: Blob :: Database -> (Ptr CBlob) -> Blob
+ Database.SQLite3.Direct: backupFinish :: Backup -> IO (Either Error ())
+ Database.SQLite3.Direct: backupInit :: Database -> Utf8 -> Database -> Utf8 -> IO (Either Error Backup)
+ Database.SQLite3.Direct: backupPagecount :: Backup -> IO Int
+ Database.SQLite3.Direct: backupRemaining :: Backup -> IO Int
+ Database.SQLite3.Direct: backupStep :: Backup -> Int -> IO (Either Error BackupStepResult)
+ Database.SQLite3.Direct: bindZeroBlob :: Statement -> ParamIndex -> Int -> IO (Either Error ())
+ Database.SQLite3.Direct: blobBytes :: Blob -> IO Int
+ Database.SQLite3.Direct: blobClose :: Blob -> IO (Either Error ())
+ Database.SQLite3.Direct: blobOpen :: Database -> Utf8 -> Utf8 -> Utf8 -> Int64 -> Bool -> IO (Either Error Blob)
+ Database.SQLite3.Direct: blobRead :: Blob -> Int -> Int -> IO (Either Error ByteString)
+ Database.SQLite3.Direct: blobReadBuf :: Blob -> Ptr a -> Int -> Int -> IO (Either Error ())
+ Database.SQLite3.Direct: blobReopen :: Blob -> Int64 -> IO (Either Error ())
+ Database.SQLite3.Direct: blobWrite :: Blob -> ByteString -> Int -> IO (Either Error ())
+ Database.SQLite3.Direct: data Backup
+ Database.SQLite3.Direct: data BackupStepResult
+ Database.SQLite3.Direct: data Blob
+ Database.SQLite3.Direct: errcode :: Database -> IO Error
+ Database.SQLite3.Direct: funcResultZeroBlob :: FuncContext -> Int -> IO ()
+ Database.SQLite3.Direct: getFuncContextDatabase :: FuncContext -> IO Database
+ Database.SQLite3.Direct: instance Eq Backup
+ Database.SQLite3.Direct: instance Eq BackupStepResult
+ Database.SQLite3.Direct: instance Eq Blob
+ Database.SQLite3.Direct: instance Show Backup
+ Database.SQLite3.Direct: instance Show BackupStepResult
+ Database.SQLite3.Direct: instance Show Blob
+ Database.SQLite3.Direct: setSharedCacheEnabled :: Bool -> IO (Either Error ())

Files

Database/SQLite3.hs view
@@ -38,6 +38,7 @@     bindDouble,     bindText,     bindBlob,+    bindZeroBlob,     bindNull,      -- * Reading the result row@@ -75,7 +76,9 @@     funcResultDouble,     funcResultText,     funcResultBlob,+    funcResultZeroBlob,     funcResultNull,+    getFuncContextDatabase,      -- * Create custom collations     createCollation,@@ -85,6 +88,24 @@     interrupt,     interruptibly, +    -- * Incremental blob I/O+    blobOpen,+    blobClose,+    blobReopen,+    blobBytes,+    blobRead,+    blobReadBuf,+    blobWrite,++    -- * Online Backup API+    -- | <https://www.sqlite.org/backup.html> and+    -- <https://www.sqlite.org/c3ref/backup_finish.html>+    backupInit,+    backupFinish,+    backupStep,+    backupRemaining,+    backupPagecount,+     -- * Types     Database,     Statement,@@ -93,9 +114,12 @@     ColumnType(..),     FuncContext,     FuncArgs,+    Blob,+    Backup,      -- ** Results and errors     StepResult(..),+    BackupStepResult(..),     Error(..),      -- ** Special integers@@ -111,6 +135,7 @@     , Statement     , ColumnType(..)     , StepResult(..)+    , BackupStepResult(..)     , Error(..)     , ParamIndex(..)     , ColumnIndex(..)@@ -120,6 +145,8 @@     , FuncArgs     , ArgCount(..)     , ArgIndex+    , Blob+    , Backup      -- Re-exported from Database.SQLite3.Direct without modification.     -- Note that if this module were in another package, source links would not@@ -139,10 +166,15 @@     , funcResultInt64     , funcResultDouble     , funcResultBlob+    , funcResultZeroBlob     , funcResultNull+    , getFuncContextDatabase     , lastInsertRowId     , changes     , interrupt+    , blobBytes+    , backupRemaining+    , backupPagecount     )  import qualified Database.SQLite3.Direct as Direct@@ -161,6 +193,7 @@ import Data.Text.Encoding   (encodeUtf8, decodeUtf8With) import Data.Text.Encoding.Error (UnicodeException(..), lenientDecode) import Data.Typeable+import Foreign.Ptr          (Ptr)  data SQLData     = SQLInteger    !Int64@@ -464,6 +497,11 @@     Direct.bindBlob statement parameterIndex byteString         >>= checkError (DetailStatement statement) "bind blob" +bindZeroBlob :: Statement -> ParamIndex -> Int -> IO ()+bindZeroBlob statement parameterIndex len =+    Direct.bindZeroBlob statement parameterIndex len+        >>= checkError (DetailStatement statement) "bind zeroblob"+ bindDouble :: Statement -> ParamIndex -> Double -> IO () bindDouble statement parameterIndex datum =     Direct.bindDouble statement parameterIndex datum@@ -669,3 +707,79 @@ deleteCollation db name =     Direct.deleteCollation db (toUtf8 name)         >>= checkError (DetailDatabase db) ("deleteCollation " `appendShow` name)+++-- | <https://www.sqlite.org/c3ref/blob_open.html>+--+-- Open a blob for incremental I/O.+blobOpen+    :: Database+    -> Text   -- ^ The symbolic name of the database (e.g. "main").+    -> Text   -- ^ The table name.+    -> Text   -- ^ The column name.+    -> Int64  -- ^ The @ROWID@ of the row.+    -> Bool   -- ^ Open the blob for read-write.+    -> IO Blob+blobOpen db zDb zTable zColumn rowid rw =+    Direct.blobOpen db (toUtf8 zDb) (toUtf8 zTable) (toUtf8 zColumn) rowid rw+        >>= checkError (DetailDatabase db) "blobOpen"++-- | <https://www.sqlite.org/c3ref/blob_close.html>+blobClose :: Blob -> IO ()+blobClose blob@(Direct.Blob db _) =+    Direct.blobClose blob+        >>= checkError (DetailDatabase db) "blobClose"++-- | <https://www.sqlite.org/c3ref/blob_reopen.html>+blobReopen :: Blob -> Int64 -> IO ()+blobReopen blob@(Direct.Blob db _) rowid =+    Direct.blobReopen blob rowid+        >>= checkError (DetailDatabase db) "blobReopen"++-- | <https://www.sqlite.org/c3ref/blob_read.html>+blobRead+    :: Blob+    -> Int -- ^ Number of bytes to read.+    -> Int -- ^ Offset within the blob.+    -> IO ByteString+blobRead blob@(Direct.Blob db _) len offset =+    Direct.blobRead blob len offset+        >>= checkError (DetailDatabase db) "blobRead"++blobReadBuf :: Blob -> Ptr a -> Int -> Int -> IO ()+blobReadBuf blob@(Direct.Blob db _) buf len offset =+    Direct.blobReadBuf blob buf len offset+        >>= checkError (DetailDatabase db) "blobReadBuf"++-- | <https://www.sqlite.org/c3ref/blob_write.html>+blobWrite+    :: Blob+    -> ByteString+    -> Int -- ^ Offset within the blob.+    -> IO ()+blobWrite blob@(Direct.Blob db _) bs offset =+    Direct.blobWrite blob bs offset+        >>= checkError (DetailDatabase db) "blobWrite"+++backupInit+    :: Database  -- ^ Destination database handle+    -> Text      -- ^ Destination database name+    -> Database  -- ^ Source database handle+    -> Text      -- ^ Source database name+    -> IO Backup+backupInit dstDb dstName srcDb srcName =+    Direct.backupInit dstDb (toUtf8 dstName) srcDb (toUtf8 srcName)+        >>= checkError (DetailDatabase dstDb) "backupInit"++backupFinish :: Backup -> IO (())+backupFinish backup@(Direct.Backup dstDb _) =+    Direct.backupFinish backup+        >>= checkError (DetailDatabase dstDb) "backupFinish"++backupStep :: Backup -> Int -> IO BackupStepResult+backupStep backup pages =+    Direct.backupStep backup pages+        -- it appears that sqlite does not generate an+        -- error message when sqlite3_backup_step fails+        >>= checkError (DetailMessage "failed") "backupStep"
Database/SQLite3/Bindings.hs view
@@ -5,12 +5,14 @@     -- * Connection management     c_sqlite3_open,     c_sqlite3_close,+    c_sqlite3_errcode,     c_sqlite3_errmsg,     c_sqlite3_interrupt,     c_sqlite3_trace,     CTraceCallback,     mkCTraceCallback,     c_sqlite3_get_autocommit,+    c_sqlite3_enable_shared_cache,      -- * Simple query execution     -- | <http://sqlite.org/c3ref/exec.html>@@ -37,6 +39,7 @@     -- * Binding Values To Prepared Statements     -- | <http://www.sqlite.org/c3ref/bind_blob.html>     c_sqlite3_bind_blob,+    c_sqlite3_bind_zeroblob,     c_sqlite3_bind_text,     c_sqlite3_bind_double,     c_sqlite3_bind_int64,@@ -97,7 +100,29 @@     c_sqlite3_free,      -- * Extensions-    c_sqlite3_enable_load_extension+    c_sqlite3_enable_load_extension,++    -- * Write-Ahead Log Commit Hook+    c_sqlite3_wal_hook,+    CWalHook,+    mkCWalHook,++    -- * Incremental blob I/O+    c_sqlite3_blob_open,+    c_sqlite3_blob_close,+    c_sqlite3_blob_reopen,+    c_sqlite3_blob_bytes,+    c_sqlite3_blob_read,+    c_sqlite3_blob_write,++    -- * Online Backup API+    -- | <https://www.sqlite.org/backup.html> and+    -- <https://www.sqlite.org/c3ref/backup_finish.html>+    c_sqlite3_backup_init,+    c_sqlite3_backup_finish,+    c_sqlite3_backup_step,+    c_sqlite3_backup_remaining,+    c_sqlite3_backup_pagecount, ) where  import Database.SQLite3.Bindings.Types@@ -117,6 +142,10 @@     c_sqlite3_close :: Ptr CDatabase -> IO CError  -- | <http://www.sqlite.org/c3ref/errcode.html>+foreign import ccall "sqlite3_errcode"+    c_sqlite3_errcode :: Ptr CDatabase -> IO CError++-- | <http://www.sqlite.org/c3ref/errcode.html> foreign import ccall "sqlite3_errmsg"     c_sqlite3_errmsg :: Ptr CDatabase -> IO CString @@ -137,7 +166,11 @@ foreign import ccall unsafe "sqlite3_get_autocommit"     c_sqlite3_get_autocommit :: Ptr CDatabase -> IO CInt +-- | <https://www.sqlite.org/c3ref/enable_shared_cache.html>+foreign import ccall unsafe "sqlite3_enable_shared_cache"+    c_sqlite3_enable_shared_cache :: CInt -> IO CError + foreign import ccall "sqlite3_exec"     c_sqlite3_exec         :: Ptr CDatabase@@ -264,6 +297,10 @@         -> Ptr CDestructor         -> IO CError +foreign import ccall unsafe "sqlite3_bind_zeroblob"+    c_sqlite3_bind_zeroblob+        :: Ptr CStatement -> CParamIndex -> CInt -> IO CError+ foreign import ccall unsafe "sqlite3_bind_text"     c_sqlite3_bind_text         :: Ptr CStatement@@ -429,3 +466,67 @@ -- | <http://sqlite.org/c3ref/enable_load_extension.html> foreign import ccall "sqlite3_enable_load_extension"     c_sqlite3_enable_load_extension :: Ptr CDatabase -> Bool -> IO CError+++-- | <https://www.sqlite.org/c3ref/wal_hook.html>+foreign import ccall unsafe "sqlite3_wal_hook"+    c_sqlite3_wal_hook :: Ptr CDatabase -> FunPtr CWalHook -> Ptr a -> IO (Ptr ())++type CWalHook = Ptr () -> Ptr CDatabase -> CString -> CInt -> IO CError++foreign import ccall "wrapper"+    mkCWalHook :: CWalHook -> IO (FunPtr CWalHook)+++-- | <https://www.sqlite.org/c3ref/blob_open.html>+foreign import ccall "sqlite3_blob_open"+    c_sqlite3_blob_open+        :: Ptr CDatabase+        -> CString         -- ^ Database name+        -> CString         -- ^ Table name+        -> CString         -- ^ Column name+        -> Int64           -- ^ Row ROWID+        -> CInt            -- ^ Flags+        -> Ptr (Ptr CBlob) -- ^ OUT: Blob handle, will be NULL on error+        -> IO CError++-- | <https://www.sqlite.org/c3ref/blob_close.html>+foreign import ccall "sqlite3_blob_close"+    c_sqlite3_blob_close :: Ptr CBlob -> IO CError++-- | <https://www.sqlite.org/c3ref/blob_reopen.html>+foreign import ccall "sqlite3_blob_reopen"+    c_sqlite3_blob_reopen :: Ptr CBlob -> Int64 -> IO CError++-- | <https://www.sqlite.org/c3ref/blob_bytes.html>+foreign import ccall unsafe "sqlite3_blob_bytes"+    c_sqlite3_blob_bytes :: Ptr CBlob -> IO CInt++-- | <https://www.sqlite.org/c3ref/blob_read.html>+foreign import ccall "sqlite3_blob_read"+    c_sqlite3_blob_read :: Ptr CBlob -> Ptr a -> CInt -> CInt -> IO CError++-- | <https://www.sqlite.org/c3ref/blob_write.html>+foreign import ccall "sqlite3_blob_write"+    c_sqlite3_blob_write :: Ptr CBlob -> Ptr a -> CInt -> CInt -> IO CError+++foreign import ccall "sqlite3_backup_init"+    c_sqlite3_backup_init+        :: Ptr CDatabase  -- ^ Destination database handle+        -> CString        -- ^ Destination database name+        -> Ptr CDatabase  -- ^ Source database handle+        -> CString        -- ^ Source database name+        -> IO (Ptr CBackup)++foreign import ccall "sqlite3_backup_finish"+    c_sqlite3_backup_finish :: Ptr CBackup -> IO CError++foreign import ccall "sqlite3_backup_step"+    c_sqlite3_backup_step :: Ptr CBackup -> CInt -> IO CError++foreign import ccall unsafe "sqlite3_backup_remaining"+    c_sqlite3_backup_remaining :: Ptr CBackup -> IO CInt++foreign import ccall unsafe "sqlite3_backup_pagecount"+    c_sqlite3_backup_pagecount :: Ptr CBackup -> IO CInt
Database/SQLite3/Bindings/Types.hsc view
@@ -9,6 +9,8 @@     CStatement,     CValue,     CContext,+    CBlob,+    CBackup,      -- * Enumerations @@ -118,6 +120,16 @@ -- -- @CContext@ = @sqlite3_context@ data CContext++-- | <https://www.sqlite.org/c3ref/blob.html>+--+-- @CBlob@ = @sqlite3_blob@+data CBlob++-- | <https://www.sqlite.org/c3ref/backup.html>+--+-- @CBackup@ = @sqlite3_backup@+data CBackup  -- | Index of a parameter in a parameterized query. -- Parameter indices start from 1.
Database/SQLite3/Direct.hs view
@@ -12,9 +12,11 @@     -- * Connection management     open,     close,+    errcode,     errmsg,     setTrace,     getAutoCommit,+    setSharedCacheEnabled,      -- * Simple query execution     -- | <http://sqlite.org/c3ref/exec.html>@@ -44,6 +46,7 @@     bindDouble,     bindText,     bindBlob,+    bindZeroBlob,     bindNull,      -- * Reading the result row@@ -78,7 +81,9 @@     funcResultDouble,     funcResultText,     funcResultBlob,+    funcResultZeroBlob,     funcResultNull,+    getFuncContextDatabase,      -- * Create custom collations     createCollation,@@ -87,15 +92,36 @@     -- * Interrupting a long-running query     interrupt, +    -- * Incremental blob I/O+    blobOpen,+    blobClose,+    blobReopen,+    blobBytes,+    blobRead,+    blobReadBuf,+    blobWrite,++    -- * Online Backup API+    -- | <https://www.sqlite.org/backup.html> and+    -- <https://www.sqlite.org/c3ref/backup_finish.html>+    backupInit,+    backupFinish,+    backupStep,+    backupRemaining,+    backupPagecount,+     -- * Types     Database(..),     Statement(..),     ColumnType(..),     FuncContext(..),     FuncArgs(..),+    Blob(..),+    Backup(..),      -- ** Results and errors     StepResult(..),+    BackupStepResult(..),     Error(..),      -- ** Special types@@ -136,6 +162,11 @@     | Done     deriving (Eq, Show) +data BackupStepResult+    = BackupOK   -- ^ There are still more pages to be copied.+    | BackupDone -- ^ All pages were successfully copied.+    deriving (Eq, Show)+ -- | A 'ByteString' containing UTF8-encoded text with no NUL characters. newtype Utf8 = Utf8 ByteString     deriving (Eq, Ord)@@ -198,6 +229,13 @@         ErrorDone -> Right Done         err       -> Left err +toBackupStepResult :: CError -> Result BackupStepResult+toBackupStepResult code =+    case decodeError code of+        ErrorOK   -> Right BackupOK+        ErrorDone -> Right BackupDone+        err       -> Left err+ -- | The context in which a custom SQL function is executed. newtype FuncContext = FuncContext (Ptr CContext)     deriving (Eq, Show)@@ -205,6 +243,17 @@ -- | The arguments of a custom SQL function. data FuncArgs = FuncArgs CArgCount (Ptr (Ptr CValue)) +-- | The type of blob handles used for incremental blob I/O+data Blob = Blob Database (Ptr CBlob) -- we include the db handle to use in+    deriving (Eq, Show)               -- error messages since it cannot+                                      -- be retrieved any other way++-- | A handle for an online backup process.+data Backup = Backup Database (Ptr CBackup)+    deriving (Eq, Show)+-- we include the destination db handle to use in error messages since+-- it cannot be retrieved any other way+ ------------------------------------------------------------------------  -- | <http://www.sqlite.org/c3ref/open.html>@@ -245,6 +294,11 @@     c_sqlite3_interrupt db  -- | <http://www.sqlite.org/c3ref/errcode.html>+errcode :: Database -> IO Error+errcode (Database db) =+    decodeError <$> c_sqlite3_errcode db++-- | <http://www.sqlite.org/c3ref/errcode.html> errmsg :: Database -> IO Utf8 errmsg (Database db) =     c_sqlite3_errmsg db >>= packUtf8 (Utf8 BS.empty) id@@ -368,6 +422,16 @@ getAutoCommit (Database db) =     (/= 0) <$> c_sqlite3_get_autocommit db ++-- | <https://www.sqlite.org/c3ref/enable_shared_cache.html>+--+-- Enable or disable shared cache for all future connections.+setSharedCacheEnabled :: Bool -> IO (Either Error ())+setSharedCacheEnabled val =+    toResult () <$> c_sqlite3_enable_shared_cache+        (if val then 1 else 0)++ -- | <http://www.sqlite.org/c3ref/prepare.html> -- -- If the query contains no SQL statements, this returns@@ -483,6 +547,11 @@         toResult () <$>             c_sqlite3_bind_blob stmt (toFFI idx) ptr len c_SQLITE_TRANSIENT +bindZeroBlob :: Statement -> ParamIndex -> Int -> IO (Either Error ())+bindZeroBlob (Statement stmt) idx len =+    toResult () <$>+        c_sqlite3_bind_zeroblob stmt (toFFI idx) (fromIntegral len)+ bindNull :: Statement -> ParamIndex -> IO (Either Error ()) bindNull (Statement stmt) idx =     toResult () <$> c_sqlite3_bind_null stmt (toFFI idx)@@ -639,7 +708,7 @@  -- call c_sqlite3_result_error in the event of an error catchAsResultError :: Ptr CContext -> IO () -> IO ()-catchAsResultError ctx action = catch action $ \exn -> do+catchAsResultError ctx action = E.catch action $ \exn -> do     let msg = show (exn :: SomeException)     withCAStringLen msg $ \(ptr, len) ->         c_sqlite3_result_error ctx ptr (fromIntegral len)@@ -712,11 +781,23 @@     unsafeUseAsCStringLenNoNull value $ \ptr len ->         c_sqlite3_result_blob ctx ptr len c_SQLITE_TRANSIENT +funcResultZeroBlob :: FuncContext -> Int -> IO ()+funcResultZeroBlob (FuncContext ctx) len =+    c_sqlite3_result_zeroblob ctx (fromIntegral len)+ funcResultNull :: FuncContext -> IO () funcResultNull (FuncContext ctx) =     c_sqlite3_result_null ctx +-- | <https://www.sqlite.org/c3ref/context_db_handle.html>+getFuncContextDatabase :: FuncContext -> IO Database+getFuncContextDatabase (FuncContext ctx) = do+    db <- c_sqlite3_context_db_handle ctx+    if db == nullPtr+        then fail $ "sqlite3_context_db_handle(" ++ show ctx ++ ") returned NULL"+        else return (Database db) + -- Deallocate the function pointer to the comparison function used to -- implement a custom collation destroyCCompare :: CFuncDestroy ()@@ -769,3 +850,110 @@ setLoadExtensionEnabled :: Database -> Bool -> IO (Either Error ()) setLoadExtensionEnabled (Database db) enabled = do     toResult () <$> c_sqlite3_enable_load_extension db enabled+++-- | <https://www.sqlite.org/c3ref/blob_open.html>+--+-- Open a blob for incremental I/O.+blobOpen+    :: Database+    -> Utf8   -- ^ The symbolic name of the database (e.g. "main").+    -> Utf8   -- ^ The table name.+    -> Utf8   -- ^ The column name.+    -> Int64  -- ^ The @ROWID@ of the row.+    -> Bool   -- ^ Open the blob for read-write.+    -> IO (Either Error Blob)+blobOpen (Database db) (Utf8 zDb) (Utf8 zTable) (Utf8 zColumn) rowid rw =+    BS.useAsCString zDb $ \ptrDb ->+    BS.useAsCString zTable $ \ptrTable ->+    BS.useAsCString zColumn $ \ptrColumn ->+    alloca $ \ptrBlob -> do+        c_sqlite3_blob_open db ptrDb ptrTable ptrColumn rowid flags ptrBlob+            >>= toResultM (Blob (Database db) <$> peek ptrBlob)+  where+    flags = if rw then 1 else 0++-- | <https://www.sqlite.org/c3ref/blob_close.html>+blobClose :: Blob -> IO (Either Error ())+blobClose (Blob _ blob) =+    toResult () <$> c_sqlite3_blob_close blob++-- | <https://www.sqlite.org/c3ref/blob_reopen.html>+blobReopen :: Blob -> Int64 -> IO (Either Error ())+blobReopen (Blob _ blob) rowid =+    toResult () <$> c_sqlite3_blob_reopen blob rowid++-- | <https://www.sqlite.org/c3ref/blob_bytes.html>+blobBytes :: Blob -> IO Int+blobBytes (Blob _ blob) =+    fromIntegral <$> c_sqlite3_blob_bytes blob++-- | <https://www.sqlite.org/c3ref/blob_read.html>+blobRead+    :: Blob+    -> Int -- ^ Number of bytes to read.+    -> Int -- ^ Offset within the blob.+    -> IO (Either Error ByteString)+blobRead blob len offset =+    -- we do not use allocaBytes here because it deallocates its buffer+    -- which would necessitate copying it+    -- instead we use mallocBytes and mask to ensure both exception+    -- safety and that the buffer is not copied any times+    mask $ \restore -> do+        buf <- mallocBytes len+        r <- restore (blobReadBuf blob buf len offset)+            `onException` (free buf)+        case r of+            Left err -> free buf >> return (Left err)+            Right () -> do+                bs <- BSU.unsafePackCStringFinalizer buf len (free buf)+                return (Right bs)++blobReadBuf :: Blob -> Ptr a -> Int -> Int -> IO (Either Error ())+blobReadBuf (Blob _ blob) buf len offset =+    toResult () <$>+        c_sqlite3_blob_read blob buf (fromIntegral len) (fromIntegral offset)++-- | <https://www.sqlite.org/c3ref/blob_write.html>+blobWrite+    :: Blob+    -> ByteString+    -> Int -- ^ Offset within the blob.+    -> IO (Either Error ())+blobWrite (Blob _ blob) bs offset =+    BSU.unsafeUseAsCStringLen bs $ \(buf, len) ->+        toResult () <$>+            c_sqlite3_blob_write blob buf (fromIntegral len) (fromIntegral offset)+++backupInit+    :: Database  -- ^ Destination database handle+    -> Utf8      -- ^ Destination database name+    -> Database  -- ^ Source database handle+    -> Utf8      -- ^ Source database name+    -> IO (Either Error Backup)+backupInit (Database dstDb) (Utf8 dstName) (Database srcDb) (Utf8 srcName) =+    BS.useAsCString dstName $ \dstName' ->+    BS.useAsCString srcName $ \srcName' -> do+        r <- c_sqlite3_backup_init dstDb dstName' srcDb srcName'+        if r == nullPtr+            then Left <$> errcode (Database dstDb)+            else return (Right (Backup (Database dstDb) r))++backupFinish :: Backup -> IO (Either Error ())+backupFinish (Backup _ backup) =+    toResult () <$>+        c_sqlite3_backup_finish backup++backupStep :: Backup -> Int -> IO (Either Error BackupStepResult)+backupStep (Backup _ backup) pages =+    toBackupStepResult <$>+        c_sqlite3_backup_step backup (fromIntegral pages)++backupRemaining :: Backup -> IO Int+backupRemaining (Backup _ backup) =+    fromIntegral <$> c_sqlite3_backup_remaining backup++backupPagecount :: Backup -> IO Int+backupPagecount (Backup _ backup) =+    fromIntegral <$> c_sqlite3_backup_pagecount backup
changelog view
@@ -1,3 +1,23 @@+v2.3.15+	* Add support for the online backup API++	* Add support for incremental blob I/O++	* Add support for zeroblobs++	* Add support for enabling/disabling the shared cache mode++	* Add low-level bindings to sqlite3_wal_hook++	* Add function for retrieving the db handle from a custom function+	  context.++	* Add bindings for sqlite3_errcode++	* Improve Travis CI coverage to cover more GHC versions (GHC 7.4 and higher)++	* Big thanks to Mario Titas and Marcin Tolysz for the above!+ v2.3.14 	* Add custom functions, aggregates and collations. 
direct-sqlite.cabal view
@@ -1,5 +1,5 @@ name: direct-sqlite-version: 2.3.14+version: 2.3.15 build-type: Simple license: BSD3 license-file: LICENSE
test/Main.hs view
@@ -60,6 +60,7 @@     , TestLabel "CustomFuncErr" . testCustomFunctionError     , TestLabel "CustomAggr"    . testCustomAggragate     , TestLabel "CustomColl"    . testCustomCollation+    , TestLabel "IncrBlobIO"    . testIncrementalBlobIO     ] ++     (if rtsSupportsBoundThreads then     [ TestLabel "Interrupt"     . testInterrupt@@ -248,6 +249,7 @@ testBind TestEnv{..} = TestCase $ do   bracket (prepare conn "SELECT ?") finalize testBind1   bracket (prepare conn "SELECT ?+?") finalize testBind2+  bracket (prepare conn "SELECT ?,?") finalize testBind3   where     testBind1 stmt = do       let params =  [SQLInteger 3]@@ -265,6 +267,16 @@       Done <- step stmt       assertEqual "two params param" [SQLInteger 2] res +    testBind3 stmt = do+      let len = 7+          bs = B.replicate len 0+      bindBlob stmt 1 bs+      bindZeroBlob stmt 2 len+      Row <- step stmt+      res <- columns stmt+      Done <- step stmt+      assertEqual "blob vs. zeroblob" [SQLBlob bs, SQLBlob bs] res+ -- Test bindParameterCount testBindParamCounts :: TestEnv -> Test testBindParamCounts TestEnv{..} = TestCase $ do@@ -797,6 +809,23 @@   where     -- order by length first, then by lexicographical order     cmpLen s1 s2 = compare (T.length s1) (T.length s2) <> compare s1 s2++testIncrementalBlobIO :: TestEnv -> Test+testIncrementalBlobIO TestEnv{..} = TestCase $ do+  withConn $ \conn -> do+    exec conn "CREATE TABLE tbl (n BLOB)"+    exec conn "INSERT INTO tbl(rowid,n) VALUES (1,'abcdefg')"+    blob <- blobOpen conn "main" "tbl" "n" 1 True+    l <- blobBytes blob+    assertEqual "blobBytes" 7 l+    s <- blobRead blob 4 2+    assertEqual "blobRead" "cdef" s+    blobWrite blob "BC" 1+    blobClose blob+    withStmt conn "SELECT n FROM tbl" $ \stmt -> do+      Row <- step stmt+      s' <- columnBlob stmt 0+      assertEqual "blobWrite" "aBCdefg" s'  testInterrupt :: TestEnv -> Test testInterrupt TestEnv{..} = TestCase $