{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE OverloadedStrings #-}

module Squeather.Internal where

import qualified Control.Exception as Exception
import Control.Exception (throwIO)
import Control.Monad (when)
import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import Data.Int (Int64)
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Encoding
import qualified Foreign
import Foreign.C.Types (CInt(CInt), CChar, CUChar)
import Foreign (Ptr, FunPtr, ForeignPtr)

import Squeather.Internal.Bindings (SQLData(SQLNull, SQLText, SQLFloat, SQLInteger, SQLBlob))
import qualified Squeather.Internal.Bindings as Bindings
import Squeather.Internal.Types (ErrorFlag, StepResult, OpenFlags)
import qualified Squeather.Internal.Types as Types

-- | SQLite3 database handle
data C'sqlite3

-- | SQLite3 statement handle
data C'sqlite3_stmt

-- | Void
data C'void

-- | Database handle.  To create a database handle, use 'open'.
-- The resources behind the handle are automatically destroyed when
-- there are no remaining references to the 'Database', so Squeather
-- provides no @close@ function.
data Database = Database
  { Database -> ForeignPtr C'sqlite3
dbPointer :: ForeignPtr C'sqlite3
  , Database -> Text
dbFilename :: Text
  -- ^ Used only for error messages.
  } deriving (Database -> Database -> Bool
(Database -> Database -> Bool)
-> (Database -> Database -> Bool) -> Eq Database
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Database -> Database -> Bool
$c/= :: Database -> Database -> Bool
== :: Database -> Database -> Bool
$c== :: Database -> Database -> Bool
Eq, Eq Database
Eq Database
-> (Database -> Database -> Ordering)
-> (Database -> Database -> Bool)
-> (Database -> Database -> Bool)
-> (Database -> Database -> Bool)
-> (Database -> Database -> Bool)
-> (Database -> Database -> Database)
-> (Database -> Database -> Database)
-> Ord Database
Database -> Database -> Bool
Database -> Database -> Ordering
Database -> Database -> Database
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Database -> Database -> Database
$cmin :: Database -> Database -> Database
max :: Database -> Database -> Database
$cmax :: Database -> Database -> Database
>= :: Database -> Database -> Bool
$c>= :: Database -> Database -> Bool
> :: Database -> Database -> Bool
$c> :: Database -> Database -> Bool
<= :: Database -> Database -> Bool
$c<= :: Database -> Database -> Bool
< :: Database -> Database -> Bool
$c< :: Database -> Database -> Bool
compare :: Database -> Database -> Ordering
$ccompare :: Database -> Database -> Ordering
$cp1Ord :: Eq Database
Ord, Int -> Database -> ShowS
[Database] -> ShowS
Database -> String
(Int -> Database -> ShowS)
-> (Database -> String) -> ([Database] -> ShowS) -> Show Database
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Database] -> ShowS
$cshowList :: [Database] -> ShowS
show :: Database -> String
$cshow :: Database -> String
showsPrec :: Int -> Database -> ShowS
$cshowsPrec :: Int -> Database -> ShowS
Show)

-- | Statement handle.  To create a statement handle, use 'prepare'.
-- The resources behind the Statement are automatically destroyed
-- when there are no remaining references to the 'Statement', so
-- Squeather provides no @finalize@ function.
data Statement = Statement
  { Statement -> ForeignPtr C'sqlite3_stmt
stmtPointer :: ForeignPtr C'sqlite3_stmt
  , Statement -> Text
stmtSql :: Text
  -- ^ SQL used to make the statement
  , Statement -> Database
stmtDb :: Database
  -- ^ Database used to make this statement
  } deriving (Statement -> Statement -> Bool
(Statement -> Statement -> Bool)
-> (Statement -> Statement -> Bool) -> Eq Statement
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Statement -> Statement -> Bool
$c/= :: Statement -> Statement -> Bool
== :: Statement -> Statement -> Bool
$c== :: Statement -> Statement -> Bool
Eq, Eq Statement
Eq Statement
-> (Statement -> Statement -> Ordering)
-> (Statement -> Statement -> Bool)
-> (Statement -> Statement -> Bool)
-> (Statement -> Statement -> Bool)
-> (Statement -> Statement -> Bool)
-> (Statement -> Statement -> Statement)
-> (Statement -> Statement -> Statement)
-> Ord Statement
Statement -> Statement -> Bool
Statement -> Statement -> Ordering
Statement -> Statement -> Statement
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Statement -> Statement -> Statement
$cmin :: Statement -> Statement -> Statement
max :: Statement -> Statement -> Statement
$cmax :: Statement -> Statement -> Statement
>= :: Statement -> Statement -> Bool
$c>= :: Statement -> Statement -> Bool
> :: Statement -> Statement -> Bool
$c> :: Statement -> Statement -> Bool
<= :: Statement -> Statement -> Bool
$c<= :: Statement -> Statement -> Bool
< :: Statement -> Statement -> Bool
$c< :: Statement -> Statement -> Bool
compare :: Statement -> Statement -> Ordering
$ccompare :: Statement -> Statement -> Ordering
$cp1Ord :: Eq Statement
Ord, Int -> Statement -> ShowS
[Statement] -> ShowS
Statement -> String
(Int -> Statement -> ShowS)
-> (Statement -> String)
-> ([Statement] -> ShowS)
-> Show Statement
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Statement] -> ShowS
$cshowList :: [Statement] -> ShowS
show :: Statement -> String
$cshow :: Statement -> String
showsPrec :: Int -> Statement -> ShowS
$cshowsPrec :: Int -> Statement -> ShowS
Show)

-- | Errors produced by the Squeather library (as opposed to being
-- caused directly by the underlying SQLite3 C library.)
data SqueatherErrorFlag
  = ParameterNotFound
  -- ^ Named parameter for SQL statement not found
  | ExecFailed
  -- ^ The 'exec' function found an error string
  | IntConversion
  -- ^ Failed to convert an 'Int' to a 'CInt' or vice-versa because
  -- the values were out of range.
  | UnknownColumnType CInt
  -- ^ 'sqlite3_column_type' returned a type Squeather didn't
  -- identify.
  | UnknownSqliteError CInt
  -- ^ SQLite returned an error code that is uknown to Squeather.
  | IncompleteBackup
  -- ^ A backup was started, but it did not finish running.
  | Bug
  -- ^ These failures should never happen and indicate a bug in
  -- Squeather.
  | ColumnNameNull Int
  -- ^ The call to 'sqlite3_column_name' returned a null pointer.

  deriving (SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
(SqueatherErrorFlag -> SqueatherErrorFlag -> Bool)
-> (SqueatherErrorFlag -> SqueatherErrorFlag -> Bool)
-> Eq SqueatherErrorFlag
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
$c/= :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
== :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
$c== :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
Eq, Eq SqueatherErrorFlag
Eq SqueatherErrorFlag
-> (SqueatherErrorFlag -> SqueatherErrorFlag -> Ordering)
-> (SqueatherErrorFlag -> SqueatherErrorFlag -> Bool)
-> (SqueatherErrorFlag -> SqueatherErrorFlag -> Bool)
-> (SqueatherErrorFlag -> SqueatherErrorFlag -> Bool)
-> (SqueatherErrorFlag -> SqueatherErrorFlag -> Bool)
-> (SqueatherErrorFlag -> SqueatherErrorFlag -> SqueatherErrorFlag)
-> (SqueatherErrorFlag -> SqueatherErrorFlag -> SqueatherErrorFlag)
-> Ord SqueatherErrorFlag
SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
SqueatherErrorFlag -> SqueatherErrorFlag -> Ordering
SqueatherErrorFlag -> SqueatherErrorFlag -> SqueatherErrorFlag
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SqueatherErrorFlag -> SqueatherErrorFlag -> SqueatherErrorFlag
$cmin :: SqueatherErrorFlag -> SqueatherErrorFlag -> SqueatherErrorFlag
max :: SqueatherErrorFlag -> SqueatherErrorFlag -> SqueatherErrorFlag
$cmax :: SqueatherErrorFlag -> SqueatherErrorFlag -> SqueatherErrorFlag
>= :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
$c>= :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
> :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
$c> :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
<= :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
$c<= :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
< :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
$c< :: SqueatherErrorFlag -> SqueatherErrorFlag -> Bool
compare :: SqueatherErrorFlag -> SqueatherErrorFlag -> Ordering
$ccompare :: SqueatherErrorFlag -> SqueatherErrorFlag -> Ordering
$cp1Ord :: Eq SqueatherErrorFlag
Ord, Int -> SqueatherErrorFlag -> ShowS
[SqueatherErrorFlag] -> ShowS
SqueatherErrorFlag -> String
(Int -> SqueatherErrorFlag -> ShowS)
-> (SqueatherErrorFlag -> String)
-> ([SqueatherErrorFlag] -> ShowS)
-> Show SqueatherErrorFlag
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SqueatherErrorFlag] -> ShowS
$cshowList :: [SqueatherErrorFlag] -> ShowS
show :: SqueatherErrorFlag -> String
$cshow :: SqueatherErrorFlag -> String
showsPrec :: Int -> SqueatherErrorFlag -> ShowS
$cshowsPrec :: Int -> SqueatherErrorFlag -> ShowS
Show)

-- | Exceptions.  Squeather indicates all errors (even those arising
-- from possible bugs) by throwing exceptions of this type.
data Error = Error
  { Error -> Text
errorContext :: Text
  -- ^ Gives a context where this error occured, such as a SELECT
  -- query or a filename passed to @open@.
  , Error -> Either ErrorFlag SqueatherErrorFlag
errorFlag :: Either ErrorFlag SqueatherErrorFlag
  -- ^ Either the error flag returned by SQLite library, or the flag
  -- produced by this library.
  , Error -> Text
errorText :: Text
  -- ^ The text description of the error, as returned by SQLite or
  -- as created by Squeather.
  , Error -> Text
errorFilename :: Text
  -- ^ The filename of the database giving rise to the error.
  } deriving (Error -> Error -> Bool
(Error -> Error -> Bool) -> (Error -> Error -> Bool) -> Eq Error
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Error -> Error -> Bool
$c/= :: Error -> Error -> Bool
== :: Error -> Error -> Bool
$c== :: Error -> Error -> Bool
Eq, Eq Error
Eq Error
-> (Error -> Error -> Ordering)
-> (Error -> Error -> Bool)
-> (Error -> Error -> Bool)
-> (Error -> Error -> Bool)
-> (Error -> Error -> Bool)
-> (Error -> Error -> Error)
-> (Error -> Error -> Error)
-> Ord Error
Error -> Error -> Bool
Error -> Error -> Ordering
Error -> Error -> Error
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Error -> Error -> Error
$cmin :: Error -> Error -> Error
max :: Error -> Error -> Error
$cmax :: Error -> Error -> Error
>= :: Error -> Error -> Bool
$c>= :: Error -> Error -> Bool
> :: Error -> Error -> Bool
$c> :: Error -> Error -> Bool
<= :: Error -> Error -> Bool
$c<= :: Error -> Error -> Bool
< :: Error -> Error -> Bool
$c< :: Error -> Error -> Bool
compare :: Error -> Error -> Ordering
$ccompare :: Error -> Error -> Ordering
$cp1Ord :: Eq Error
Ord, Int -> Error -> ShowS
[Error] -> ShowS
Error -> String
(Int -> Error -> ShowS)
-> (Error -> String) -> ([Error] -> ShowS) -> Show Error
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Error] -> ShowS
$cshowList :: [Error] -> ShowS
show :: Error -> String
$cshow :: Error -> String
showsPrec :: Int -> Error -> ShowS
$cshowsPrec :: Int -> Error -> ShowS
Show)

instance Exception.Exception Error

-- | <https://www.sqlite.org/c3ref/extended_result_codes.html>
foreign import ccall unsafe "sqlite3_extended_result_codes" sqlite3_extended_result_codes
  :: Ptr C'sqlite3
  -> Int
  -- ^ On or off
  -> IO CInt

-- | <https://www.sqlite.org/c3ref/open.html>
foreign import ccall unsafe "sqlite3_open_v2" sqlite3_open_v2
  :: Ptr CChar
  -- ^ Database filename, UTF-8
  -> Ptr (Ptr C'sqlite3)
  -- ^ OUT: SQLite db handle
  -> CInt
  -- ^ Flags
  -> Ptr CChar
  -- ^ VFS module to use
  -> IO CInt

-- | <https://www.sqlite.org/c3ref/errcode.html>
foreign import ccall unsafe "sqlite3_errmsg" sqlite3_errmsg
  :: Ptr C'sqlite3
  -> IO (Ptr CChar)

-- | Reads a UTF-8 text.
readUtf8 :: Ptr CChar -> IO Text
readUtf8 :: Ptr CChar -> IO Text
readUtf8 Ptr CChar
cstr = do
  ByteString
bs <- Ptr CChar -> IO ByteString
ByteString.packCString Ptr CChar
cstr
  Text -> IO Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> IO Text) -> (ByteString -> Text) -> ByteString -> IO Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
Encoding.decodeUtf8 (ByteString -> IO Text) -> ByteString -> IO Text
forall a b. (a -> b) -> a -> b
$ ByteString
bs

-- | Writes a UTF-8 text for foreign function use.
writeUtf8 :: Text -> (Ptr CChar -> IO a) -> IO a
writeUtf8 :: Text -> (Ptr CChar -> IO a) -> IO a
writeUtf8 Text
txt Ptr CChar -> IO a
cback = do
  let bs :: ByteString
bs = Text -> ByteString
Encoding.encodeUtf8 Text
txt
  ByteString -> (Ptr CChar -> IO a) -> IO a
forall a. ByteString -> (Ptr CChar -> IO a) -> IO a
ByteString.useAsCString ByteString
bs Ptr CChar -> IO a
cback

-- | Like 'writeUtf8' but instead returns a CStringLen.
writeUtf8Len :: Text -> ((Ptr CChar, Int) -> IO a) -> IO a
writeUtf8Len :: Text -> ((Ptr CChar, Int) -> IO a) -> IO a
writeUtf8Len Text
txt (Ptr CChar, Int) -> IO a
cback = do
  let bs :: ByteString
bs = Text -> ByteString
Encoding.encodeUtf8 Text
txt
  ByteString -> ((Ptr CChar, Int) -> IO a) -> IO a
forall a. ByteString -> ((Ptr CChar, Int) -> IO a) -> IO a
ByteString.useAsCStringLen ByteString
bs (Ptr CChar, Int) -> IO a
cback


-- | Checks SQLite return code.  Throws an exception if the code is
-- an error.  Otherwise, returns successfully.  Do not use this
-- function if checking the return code from a function such as
-- @sqlite3_step@; instead, use 'checkStepError'.
checkError
  :: Database
  -> Text
  -- ^ Context
  -> CInt
  -> IO ()
checkError :: Database -> Text -> CInt -> IO ()
checkError (Database ForeignPtr C'sqlite3
dbFp Text
dbFn) Text
ctx CInt
err = case CInt -> ParseErrorResult
forall a. (Integral a, Show a) => a -> ParseErrorResult
Bindings.parseError CInt
err of
  ParseErrorResult
Bindings.ParseErrorOk -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  Bindings.ParseErrorStep StepResult
_ -> Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
    { errorContext :: Text
errorContext = Text
ctx
    , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right SqueatherErrorFlag
Bug
    , errorText :: Text
errorText = Text
"Squeather.checkError: returned StepResult - should never happen"
    , errorFilename :: Text
errorFilename = Text
dbFn
    }
  Bindings.ParseErrorError ErrorFlag
flg -> ForeignPtr C'sqlite3 -> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3
dbFp ((Ptr C'sqlite3 -> IO ()) -> IO ())
-> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3
db -> do
    Ptr CChar
ptrMsg <- Ptr C'sqlite3 -> IO (Ptr CChar)
sqlite3_errmsg Ptr C'sqlite3
db
    Text
errMsg <- Ptr CChar -> IO Text
readUtf8 Ptr CChar
ptrMsg
    Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error Text
ctx (ErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. a -> Either a b
Left ErrorFlag
flg) Text
errMsg Text
dbFn
  ParseErrorResult
Bindings.ParseErrorNotFound -> Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
    { errorContext :: Text
errorContext = Text
ctx
    , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right (SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag)
-> SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. (a -> b) -> a -> b
$ CInt -> SqueatherErrorFlag
UnknownSqliteError CInt
err
    , errorText :: Text
errorText = String -> Text
Text.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
"Squeather.checkError: returned unknown error code " String -> ShowS
forall a. [a] -> [a] -> [a]
++ CInt -> String
forall a. Show a => a -> String
show CInt
err
    , errorFilename :: Text
errorFilename = Text
dbFn
    }

-- | Like 'checkError' but for use only when using
-- @sqlite3_initialize@.
checkInitError
  :: Text
  -- ^ Database filename
  -> CInt
  -> IO ()
checkInitError :: Text -> CInt -> IO ()
checkInitError Text
fn CInt
err = case CInt -> ParseErrorResult
forall a. (Integral a, Show a) => a -> ParseErrorResult
Bindings.parseError CInt
err of
  ParseErrorResult
Bindings.ParseErrorOk -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  Bindings.ParseErrorStep StepResult
_ -> Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
    { errorContext :: Text
errorContext = Text
ctx
    , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right SqueatherErrorFlag
Bug
    , errorText :: Text
errorText = Text
"Squeather.checkInitError: returned StepResult - should never happen"
    , errorFilename :: Text
errorFilename = Text
fn
    }
  Bindings.ParseErrorError ErrorFlag
res -> Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
    { errorContext :: Text
errorContext = Text
ctx
    , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = ErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. a -> Either a b
Left ErrorFlag
res
    , errorText :: Text
errorText = String -> Text
Text.pack
      (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
"Squeather.checkInitError: returned error code " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ErrorFlag -> String
forall a. Show a => a -> String
show ErrorFlag
res
    , errorFilename :: Text
errorFilename = Text
fn
    }
  ParseErrorResult
Bindings.ParseErrorNotFound -> Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
    { errorContext :: Text
errorContext = Text
ctx
    , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right (SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag)
-> SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. (a -> b) -> a -> b
$ CInt -> SqueatherErrorFlag
UnknownSqliteError CInt
err
    , errorText :: Text
errorText = String -> Text
Text.pack
      (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
"Squeather.checkInitError: returned unknown error code " String -> ShowS
forall a. [a] -> [a] -> [a]
++ CInt -> String
forall a. Show a => a -> String
show CInt
err
    , errorFilename :: Text
errorFilename = Text
fn
    }
  where
    ctx :: Text
ctx = Text
"when initializing SQLite library"

-- | Like 'checkError' but for use when using @sqlite3_step@.
checkStepError
  :: Database
  -> Text
  -- ^ Context
  -> CInt
  -> IO StepResult
checkStepError :: Database -> Text -> CInt -> IO StepResult
checkStepError (Database ForeignPtr C'sqlite3
dbFp Text
dbName) Text
ctx CInt
err = case CInt -> ParseErrorResult
forall a. (Integral a, Show a) => a -> ParseErrorResult
Bindings.parseError CInt
err of
  ParseErrorResult
Bindings.ParseErrorOk -> Error -> IO StepResult
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO StepResult) -> Error -> IO StepResult
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
    { errorContext :: Text
errorContext = Text
ctx
    , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right SqueatherErrorFlag
Bug
    , errorText :: Text
errorText = Text
"Squeather.checkStepError: returned SQLITE_OK - should never happen"
    , errorFilename :: Text
errorFilename = Text
dbName
    }
  Bindings.ParseErrorStep StepResult
r -> StepResult -> IO StepResult
forall (m :: * -> *) a. Monad m => a -> m a
return StepResult
r
  Bindings.ParseErrorError ErrorFlag
flag -> ForeignPtr C'sqlite3
-> (Ptr C'sqlite3 -> IO StepResult) -> IO StepResult
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3
dbFp ((Ptr C'sqlite3 -> IO StepResult) -> IO StepResult)
-> (Ptr C'sqlite3 -> IO StepResult) -> IO StepResult
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3
db -> do
    Ptr CChar
ptrMsg <- Ptr C'sqlite3 -> IO (Ptr CChar)
sqlite3_errmsg Ptr C'sqlite3
db
    Text
errMsg <- Ptr CChar -> IO Text
readUtf8 Ptr CChar
ptrMsg
    Error -> IO StepResult
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO StepResult) -> Error -> IO StepResult
forall a b. (a -> b) -> a -> b
$ Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error Text
ctx (ErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. a -> Either a b
Left ErrorFlag
flag) Text
errMsg Text
dbName
  ParseErrorResult
Bindings.ParseErrorNotFound -> Error -> IO StepResult
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO StepResult) -> Error -> IO StepResult
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
    { errorContext :: Text
errorContext = Text
ctx
    , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right (SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag)
-> SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. (a -> b) -> a -> b
$ CInt -> SqueatherErrorFlag
UnknownSqliteError CInt
err
    , errorText :: Text
errorText = String -> Text
Text.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
"Squeather.checkStepError: returned unknown error code " String -> ShowS
forall a. [a] -> [a] -> [a]
++ CInt -> String
forall a. Show a => a -> String
show CInt
err
    , errorFilename :: Text
errorFilename = Text
dbName
    }

-- | Opens a new 'Database'.  The 'openFlags' are used.
open
  :: Text
  -- ^ Database filename
  -> IO Database
open :: Text -> IO Database
open = OpenFlags -> Text -> IO Database
openWithFlags OpenFlags
openFlags

-- | Opens a new 'Database', with settings specified with
-- 'openFlags'.
openWithFlags
  :: OpenFlags
  -> Text
  -- ^ Database filename
  -> IO Database
openWithFlags :: OpenFlags -> Text -> IO Database
openWithFlags OpenFlags
flags Text
fn
  = Text -> (Ptr CChar -> IO Database) -> IO Database
forall a. Text -> (Ptr CChar -> IO a) -> IO a
writeUtf8 Text
fn ((Ptr CChar -> IO Database) -> IO Database)
-> (Ptr CChar -> IO Database) -> IO Database
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
fnUtf8 ->
  (Ptr (Ptr C'sqlite3) -> IO Database) -> IO Database
forall a b. Storable a => (Ptr a -> IO b) -> IO b
Foreign.alloca ((Ptr (Ptr C'sqlite3) -> IO Database) -> IO Database)
-> (Ptr (Ptr C'sqlite3) -> IO Database) -> IO Database
forall a b. (a -> b) -> a -> b
$ \Ptr (Ptr C'sqlite3)
ptrIn ->
  Ptr (Ptr C'sqlite3) -> Ptr C'sqlite3 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
Foreign.poke Ptr (Ptr C'sqlite3)
ptrIn Ptr C'sqlite3
forall a. Ptr a
Foreign.nullPtr IO () -> IO Database -> IO Database
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
  let acq :: IO CInt
acq = Ptr CChar -> Ptr (Ptr C'sqlite3) -> CInt -> Ptr CChar -> IO CInt
sqlite3_open_v2 Ptr CChar
fnUtf8 Ptr (Ptr C'sqlite3)
ptrIn (OpenFlags -> CInt
Bindings.flagsToInt OpenFlags
flags) Ptr CChar
forall a. Ptr a
Foreign.nullPtr
      rel :: p -> IO CInt
rel p
_ = Ptr (Ptr C'sqlite3) -> IO (Ptr C'sqlite3)
forall a. Storable a => Ptr a -> IO a
Foreign.peek Ptr (Ptr C'sqlite3)
ptrIn IO (Ptr C'sqlite3) -> (Ptr C'sqlite3 -> IO CInt) -> IO CInt
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Ptr C'sqlite3 -> IO CInt
sqlite3_close_v2
      use :: b -> IO (ForeignPtr C'sqlite3, b)
use b
code = do
        Ptr C'sqlite3
sqlite3 <- Ptr (Ptr C'sqlite3) -> IO (Ptr C'sqlite3)
forall a. Storable a => Ptr a -> IO a
Foreign.peek Ptr (Ptr C'sqlite3)
ptrIn
        ForeignPtr C'sqlite3
fp <- FinalizerPtr C'sqlite3
-> Ptr C'sqlite3 -> IO (ForeignPtr C'sqlite3)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
Foreign.newForeignPtr FinalizerPtr C'sqlite3
p_squeather_close_v2 Ptr C'sqlite3
sqlite3
        (ForeignPtr C'sqlite3, b) -> IO (ForeignPtr C'sqlite3, b)
forall (m :: * -> *) a. Monad m => a -> m a
return (ForeignPtr C'sqlite3
fp, b
code)
  in do
      IO CInt
sqlite3_initialize IO CInt -> (CInt -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> CInt -> IO ()
checkInitError Text
fn
      (ForeignPtr C'sqlite3
fp, CInt
code) <- IO CInt
-> (CInt -> IO CInt)
-> (CInt -> IO (ForeignPtr C'sqlite3, CInt))
-> IO (ForeignPtr C'sqlite3, CInt)
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
Exception.bracketOnError IO CInt
acq CInt -> IO CInt
forall p. p -> IO CInt
rel CInt -> IO (ForeignPtr C'sqlite3, CInt)
forall b. b -> IO (ForeignPtr C'sqlite3, b)
use
      let db :: Database
db = ForeignPtr C'sqlite3 -> Text -> Database
Database ForeignPtr C'sqlite3
fp Text
fn
      Database -> Text -> CInt -> IO ()
checkError Database
db Text
"opening database" CInt
code
      ForeignPtr C'sqlite3 -> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3
fp ((Ptr C'sqlite3 -> IO ()) -> IO ())
-> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3
ptrDb ->
        Ptr C'sqlite3 -> Int -> IO CInt
sqlite3_extended_result_codes Ptr C'sqlite3
ptrDb Int
1
          IO CInt -> (CInt -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Database -> Text -> CInt -> IO ()
checkError Database
db Text
"setting extended result codes"
      Database -> IO Database
forall (m :: * -> *) a. Monad m => a -> m a
return Database
db


-- | <https://www.sqlite.org/c3ref/prepare.html>
foreign import ccall unsafe "sqlite3_prepare_v2" sqlite3_prepare_v2
  :: Ptr C'sqlite3
  -- ^ Database handle
  -> Ptr CChar
  -- ^ SQL Statement, UTF-8
  -> CInt
  -- ^ Length of SQL statement in bytes
  -> Ptr (Ptr C'sqlite3_stmt)
  -- ^ OUT Statement handle
  -> Ptr (Ptr CChar)
  -- ^ OUT unused portion of input statement
  -> IO CInt

-- | Prepares a statement.  The corresponding C SQLite function
-- allows you to pass in a multi-statement SQL text, and retrieve
-- the unused portion for later use.  Squeather does not allow this.
-- Squeather will prepare only the first statement.
prepare
  :: Database
  -- ^ Database handle
  -> Text
  -- ^ SQL Statement, UTF-8
  -> IO Statement
prepare :: Database -> Text -> IO Statement
prepare db :: Database
db@(Database ForeignPtr C'sqlite3
dbFp Text
dbFn) Text
sql
  = Text -> ((Ptr CChar, Int) -> IO Statement) -> IO Statement
forall a. Text -> ((Ptr CChar, Int) -> IO a) -> IO a
writeUtf8Len Text
sql (((Ptr CChar, Int) -> IO Statement) -> IO Statement)
-> ((Ptr CChar, Int) -> IO Statement) -> IO Statement
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
sqlUtf8, Int
sqlLen) ->
  (Ptr (Ptr C'sqlite3_stmt) -> IO Statement) -> IO Statement
forall a b. Storable a => (Ptr a -> IO b) -> IO b
Foreign.alloca ((Ptr (Ptr C'sqlite3_stmt) -> IO Statement) -> IO Statement)
-> (Ptr (Ptr C'sqlite3_stmt) -> IO Statement) -> IO Statement
forall a b. (a -> b) -> a -> b
$ \Ptr (Ptr C'sqlite3_stmt)
ptrIn ->
  ForeignPtr C'sqlite3
-> (Ptr C'sqlite3 -> IO Statement) -> IO Statement
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3
dbFp ((Ptr C'sqlite3 -> IO Statement) -> IO Statement)
-> (Ptr C'sqlite3 -> IO Statement) -> IO Statement
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3
dbPtr -> do
    Ptr (Ptr C'sqlite3_stmt) -> Ptr C'sqlite3_stmt -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
Foreign.poke Ptr (Ptr C'sqlite3_stmt)
ptrIn Ptr C'sqlite3_stmt
forall a. Ptr a
Foreign.nullPtr
    CInt
sqlLenCInt <- Text -> Text -> Int -> IO CInt
intToCInt Text
sql Text
dbFn Int
sqlLen
    let acq :: IO CInt
acq = Ptr C'sqlite3
-> Ptr CChar
-> CInt
-> Ptr (Ptr C'sqlite3_stmt)
-> Ptr (Ptr CChar)
-> IO CInt
sqlite3_prepare_v2 Ptr C'sqlite3
dbPtr Ptr CChar
sqlUtf8 CInt
sqlLenCInt Ptr (Ptr C'sqlite3_stmt)
ptrIn Ptr (Ptr CChar)
forall a. Ptr a
Foreign.nullPtr
        rel :: p -> IO CInt
rel p
_ = Ptr (Ptr C'sqlite3_stmt) -> IO (Ptr C'sqlite3_stmt)
forall a. Storable a => Ptr a -> IO a
Foreign.peek Ptr (Ptr C'sqlite3_stmt)
ptrIn IO (Ptr C'sqlite3_stmt)
-> (Ptr C'sqlite3_stmt -> IO CInt) -> IO CInt
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Ptr C'sqlite3_stmt -> IO CInt
sqlite3_finalize
        use :: CInt -> IO Statement
use CInt
code = do
          Ptr C'sqlite3_stmt
ptrStmt <- Ptr (Ptr C'sqlite3_stmt) -> IO (Ptr C'sqlite3_stmt)
forall a. Storable a => Ptr a -> IO a
Foreign.peek Ptr (Ptr C'sqlite3_stmt)
ptrIn
          ForeignPtr C'sqlite3_stmt
fp <- FinalizerPtr C'sqlite3_stmt
-> Ptr C'sqlite3_stmt -> IO (ForeignPtr C'sqlite3_stmt)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
Foreign.newForeignPtr FinalizerPtr C'sqlite3_stmt
p_squeather_finalize Ptr C'sqlite3_stmt
ptrStmt
          Database -> Text -> CInt -> IO ()
checkError Database
db Text
sql CInt
code
          Statement -> IO Statement
forall (m :: * -> *) a. Monad m => a -> m a
return (Statement -> IO Statement) -> Statement -> IO Statement
forall a b. (a -> b) -> a -> b
$ ForeignPtr C'sqlite3_stmt -> Text -> Database -> Statement
Statement ForeignPtr C'sqlite3_stmt
fp Text
sql Database
db
    IO CInt
-> (CInt -> IO CInt) -> (CInt -> IO Statement) -> IO Statement
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
Exception.bracketOnError IO CInt
acq CInt -> IO CInt
forall p. p -> IO CInt
rel CInt -> IO Statement
use

-- | <https://www.sqlite.org/c3ref/bind_parameter_index.html>
foreign import ccall unsafe "sqlite3_bind_parameter_index" sqlite3_bind_parameter_index
  :: Ptr C'sqlite3_stmt
  -- ^ Statement
  -> Ptr CChar
  -- ^ Parameter name
  -> IO CInt
  -- ^ The index of the parameter.  Returns 0 if no matching
  -- parameter is found.

-- | Gets the index of the parameter that has the given name.
-- Throws an 'Error' with 'ParameterNotFound' if the given parameter
-- name does not exist for this statement.
getParameterIndex
  :: Statement
  -> Text
  -- ^ Look up the parameter with this name.
  -> IO CInt
getParameterIndex :: Statement -> Text -> IO CInt
getParameterIndex (Statement ForeignPtr C'sqlite3_stmt
stFp Text
stSql (Database ForeignPtr C'sqlite3
_ Text
dbFn)) Text
param
  = Text -> (Ptr CChar -> IO CInt) -> IO CInt
forall a. Text -> (Ptr CChar -> IO a) -> IO a
writeUtf8 Text
param ((Ptr CChar -> IO CInt) -> IO CInt)
-> (Ptr CChar -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
paramUtf8 ->
    ForeignPtr C'sqlite3_stmt
-> (Ptr C'sqlite3_stmt -> IO CInt) -> IO CInt
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO CInt) -> IO CInt)
-> (Ptr C'sqlite3_stmt -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
stPtr -> do
      CInt
idx <- Ptr C'sqlite3_stmt -> Ptr CChar -> IO CInt
sqlite3_bind_parameter_index Ptr C'sqlite3_stmt
stPtr Ptr CChar
paramUtf8
      if CInt
idx CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
0
        then Error -> IO CInt
forall e a. Exception e => e -> IO a
throwIO (Error -> IO CInt) -> Error -> IO CInt
forall a b. (a -> b) -> a -> b
$ Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error Text
stSql (SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right SqueatherErrorFlag
ParameterNotFound)
                (Text
"parameter not found: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
param) Text
dbFn
        else CInt -> IO CInt
forall (m :: * -> *) a. Monad m => a -> m a
return CInt
idx

-- | <https://www.sqlite.org/c3ref/bind_blob.html>
foreign import ccall safe "sqlite3_bind_blob" sqlite3_bind_blob
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> Ptr a
  -- ^ Blob
  -> CInt
  -- ^ Length
  -> FunPtr (Ptr a -> IO ())
  -- ^ Callback to dispose of the blob.  Use @SQLITE_STATIC@ if the
  -- blob is in static, unmanaged space and does not need to be
  -- freed.  Use @SQLITE_TRANSIENT@ to have SQLite make its own
  -- private copy of the data immediately.
  -> IO CInt

bindBlob
  :: Statement
  -> Text
  -- ^ Parameter name
  -> ByteString
  -- ^ Blob
  -> IO ()
bindBlob :: Statement -> Text -> ByteString -> IO ()
bindBlob st :: Statement
st@(Statement ForeignPtr C'sqlite3_stmt
stFp Text
sSql Database
db) Text
paramName ByteString
blob
  = ByteString -> ((Ptr CChar, Int) -> IO ()) -> IO ()
forall a. ByteString -> ((Ptr CChar, Int) -> IO a) -> IO a
ByteString.useAsCStringLen ByteString
blob (((Ptr CChar, Int) -> IO ()) -> IO ())
-> ((Ptr CChar, Int) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
ptrBlob, Int
blobLen) -> 
  ForeignPtr C'sqlite3_stmt -> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO ()) -> IO ())
-> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
sPtr -> do
    CInt
idx <- Statement -> Text -> IO CInt
getParameterIndex Statement
st Text
paramName
    let transient :: FunPtr b
transient = Ptr Any -> FunPtr b
forall a b. Ptr a -> FunPtr b
Foreign.castPtrToFunPtr (Ptr Any -> FunPtr b) -> (IntPtr -> Ptr Any) -> IntPtr -> FunPtr b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IntPtr -> Ptr Any
forall a. IntPtr -> Ptr a
Foreign.intPtrToPtr
          (IntPtr -> FunPtr b) -> IntPtr -> FunPtr b
forall a b. (a -> b) -> a -> b
$ IntPtr
forall a. Integral a => a
Bindings.c'SQLITE_TRANSIENT
    CInt
blobLenCInt <- Text -> Text -> Int -> IO CInt
intToCInt Text
sSql (Database -> Text
dbFilename Database
db) Int
blobLen
    CInt
rslt <- Ptr C'sqlite3_stmt
-> CInt
-> Ptr CChar
-> CInt
-> FunPtr (Ptr CChar -> IO ())
-> IO CInt
forall a.
Ptr C'sqlite3_stmt
-> CInt -> Ptr a -> CInt -> FunPtr (Ptr a -> IO ()) -> IO CInt
sqlite3_bind_blob Ptr C'sqlite3_stmt
sPtr CInt
idx Ptr CChar
ptrBlob CInt
blobLenCInt FunPtr (Ptr CChar -> IO ())
forall b. FunPtr b
transient
    Database -> Text -> CInt -> IO ()
checkError Database
db Text
sSql CInt
rslt

-- | <https://www.sqlite.org/c3ref/bind_blob.html>
foreign import ccall unsafe "sqlite3_bind_double" sqlite3_bind_double
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> Double
  -- ^ Double to bind
  -> IO CInt

bindDouble
  :: Statement
  -> Text
  -- ^ Parameter name
  -> Double
  -> IO ()
bindDouble :: Statement -> Text -> Double -> IO ()
bindDouble st :: Statement
st@(Statement ForeignPtr C'sqlite3_stmt
stFp Text
sSql Database
db) Text
paramName Double
dbl =
  ForeignPtr C'sqlite3_stmt -> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO ()) -> IO ())
-> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
sPtr -> do
    CInt
idx <- Statement -> Text -> IO CInt
getParameterIndex Statement
st Text
paramName
    CInt
rslt <- Ptr C'sqlite3_stmt -> CInt -> Double -> IO CInt
sqlite3_bind_double Ptr C'sqlite3_stmt
sPtr CInt
idx Double
dbl
    Database -> Text -> CInt -> IO ()
checkError Database
db Text
sSql CInt
rslt

-- | <https://www.sqlite.org/c3ref/bind_blob.html>
foreign import ccall unsafe "sqlite3_bind_int64" sqlite3_bind_int64
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> Int64
  -> IO CInt

bindInt64
  :: Statement
  -> Text
  -- ^ Parameter name
  -> Int64
  -> IO ()
bindInt64 :: Statement -> Text -> Int64 -> IO ()
bindInt64 st :: Statement
st@(Statement ForeignPtr C'sqlite3_stmt
stFp Text
sSql Database
db) Text
paramName Int64
int64 =
  ForeignPtr C'sqlite3_stmt -> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO ()) -> IO ())
-> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
sPtr -> do
    CInt
idx <- Statement -> Text -> IO CInt
getParameterIndex Statement
st Text
paramName
    CInt
rslt <- Ptr C'sqlite3_stmt -> CInt -> Int64 -> IO CInt
sqlite3_bind_int64 Ptr C'sqlite3_stmt
sPtr CInt
idx Int64
int64
    Database -> Text -> CInt -> IO ()
checkError Database
db Text
sSql CInt
rslt

-- | <https://www.sqlite.org/c3ref/bind_blob.html>
foreign import ccall unsafe "sqlite3_bind_null" sqlite3_bind_null
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> IO CInt

bindNull
  :: Statement
  -> Text
  -- ^ Parameter name
  -> IO ()
bindNull :: Statement -> Text -> IO ()
bindNull st :: Statement
st@(Statement ForeignPtr C'sqlite3_stmt
stFp Text
sSql Database
db) Text
paramName =
  ForeignPtr C'sqlite3_stmt -> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO ()) -> IO ())
-> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
sPtr -> do
    CInt
idx <- Statement -> Text -> IO CInt
getParameterIndex Statement
st Text
paramName
    CInt
rslt <- Ptr C'sqlite3_stmt -> CInt -> IO CInt
sqlite3_bind_null Ptr C'sqlite3_stmt
sPtr CInt
idx
    Database -> Text -> CInt -> IO ()
checkError Database
db Text
sSql CInt
rslt

-- | <https://www.sqlite.org/c3ref/bind_blob.html>
foreign import ccall unsafe "sqlite3_bind_text" sqlite3_bind_text
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> Ptr CChar
  -- ^ UTF-8 text
  -> CInt
  -- ^ Length
  -> FunPtr (Ptr a -> IO ())
  -- ^ Callback to dispose of the string.  Use @SQLITE_STATIC@ if the
  -- string is in static, unmanaged space and does not need to be
  -- freed.  Use @SQLITE_TRANSIENT@ to have SQLite make its own
  -- private copy of the data immediately.
  -> IO CInt

bindText
  :: Statement
  -> Text
  -- ^ Parameter name
  -> Text
  -- ^ Text to bind
  -> IO ()
bindText :: Statement -> Text -> Text -> IO ()
bindText st :: Statement
st@(Statement ForeignPtr C'sqlite3_stmt
stFp Text
sSql Database
db) Text
paramName Text
txt
  = Text -> ((Ptr CChar, Int) -> IO ()) -> IO ()
forall a. Text -> ((Ptr CChar, Int) -> IO a) -> IO a
writeUtf8Len Text
txt (((Ptr CChar, Int) -> IO ()) -> IO ())
-> ((Ptr CChar, Int) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
ptrTxt, Int
txtLen) ->
  ForeignPtr C'sqlite3_stmt -> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO ()) -> IO ())
-> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
sPtr -> do
    CInt
idx <- Statement -> Text -> IO CInt
getParameterIndex Statement
st Text
paramName
    let transient :: FunPtr b
transient = Ptr Any -> FunPtr b
forall a b. Ptr a -> FunPtr b
Foreign.castPtrToFunPtr (Ptr Any -> FunPtr b) -> (IntPtr -> Ptr Any) -> IntPtr -> FunPtr b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IntPtr -> Ptr Any
forall a. IntPtr -> Ptr a
Foreign.intPtrToPtr
          (IntPtr -> FunPtr b) -> IntPtr -> FunPtr b
forall a b. (a -> b) -> a -> b
$ IntPtr
forall a. Integral a => a
Bindings.c'SQLITE_TRANSIENT
    CInt
txtLenCInt <- Text -> Text -> Int -> IO CInt
intToCInt Text
sSql (Database -> Text
dbFilename Database
db) Int
txtLen
    CInt
rslt <- Ptr C'sqlite3_stmt
-> CInt
-> Ptr CChar
-> CInt
-> FunPtr (Ptr Any -> IO ())
-> IO CInt
forall a.
Ptr C'sqlite3_stmt
-> CInt -> Ptr CChar -> CInt -> FunPtr (Ptr a -> IO ()) -> IO CInt
sqlite3_bind_text Ptr C'sqlite3_stmt
sPtr CInt
idx Ptr CChar
ptrTxt CInt
txtLenCInt FunPtr (Ptr Any -> IO ())
forall b. FunPtr b
transient
    Database -> Text -> CInt -> IO ()
checkError Database
db Text
sSql CInt
rslt

-- | Binds a parameter with given SQL data to the given 'Statement'.
bindSqlData
  :: Statement
  -> Text
  -- ^ Parameter name
  -> SQLData
  -> IO ()
bindSqlData :: Statement -> Text -> SQLData -> IO ()
bindSqlData Statement
st Text
name SQLData
sqld = case SQLData
sqld of
  SQLData
SQLNull -> Statement -> Text -> IO ()
bindNull Statement
st Text
name
  SQLText Text
txt -> Statement -> Text -> Text -> IO ()
bindText Statement
st Text
name Text
txt
  SQLFloat Double
dbl -> Statement -> Text -> Double -> IO ()
bindDouble Statement
st Text
name Double
dbl
  SQLInteger Int64
i64 -> Statement -> Text -> Int64 -> IO ()
bindInt64 Statement
st Text
name Int64
i64
  SQLBlob ByteString
blob -> Statement -> Text -> ByteString -> IO ()
bindBlob Statement
st Text
name ByteString
blob

-- | <https://www.sqlite.org/c3ref/step.html>
foreign import ccall unsafe "sqlite3_step" sqlite3_step
  :: Ptr C'sqlite3_stmt
  -> IO CInt

-- | Evaluate a prepared statement.  Returns 'Types.Row' if the
-- 'Statement' has returned a row of data.  In that case, use
-- 'column' or 'columns' to get individual columns or all columns,
-- respectively.  Returns 'Types.Done' if there is no data to retrieve.
-- In that case, 'step' should not be called again without first
-- calling 'reset'.
step :: Statement -> IO StepResult
step :: Statement -> IO StepResult
step (Statement ForeignPtr C'sqlite3_stmt
stFp Text
sSql Database
db) =
  ForeignPtr C'sqlite3_stmt
-> (Ptr C'sqlite3_stmt -> IO StepResult) -> IO StepResult
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO StepResult) -> IO StepResult)
-> (Ptr C'sqlite3_stmt -> IO StepResult) -> IO StepResult
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
sPtr -> do
    CInt
rslt <- Ptr C'sqlite3_stmt -> IO CInt
sqlite3_step Ptr C'sqlite3_stmt
sPtr
    Database -> Text -> CInt -> IO StepResult
checkStepError Database
db Text
sSql CInt
rslt

-- | The number of columns returned by the prepared statement.  Can
-- be zero.  However, just because this routine returns a positive
-- number does not mean that data will be returned.  A @SELECT@
-- statement will always return a postive column count, but a
-- particular query might return no rows.
--
-- <https://www.sqlite.org/c3ref/column_count.html>
foreign import ccall unsafe "sqlite3_column_count" sqlite3_column_count
  :: Ptr C'sqlite3_stmt
  -> IO CInt

-- | <https://www.sqlite.org/c3ref/column_blob.html>
foreign import ccall unsafe "sqlite3_column_bytes" sqlite3_column_bytes
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Column index
  -> IO CInt
  -- ^ Number of bytes in the column

-- | <https://www.sqlite.org/c3ref/column_blob.html>
foreign import ccall unsafe "sqlite3_column_type" sqlite3_column_type
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> IO CInt

-- | <https://www.sqlite.org/c3ref/column_blob.html>
foreign import ccall unsafe "sqlite3_column_blob" sqlite3_column_blob
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> IO (Ptr a)
  -- ^ Pointer to result

-- | <https://www.sqlite.org/c3ref/column_blob.html>
foreign import ccall unsafe "sqlite3_column_double" sqlite3_column_double
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> IO Double

-- | <https://www.sqlite.org/c3ref/column_blob.html>
foreign import ccall unsafe "sqlite3_column_int64" sqlite3_column_int64
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> IO Int64

-- | <https://www.sqlite.org/c3ref/column_blob.html>
foreign import ccall unsafe "sqlite3_column_text" sqlite3_column_text
  :: Ptr C'sqlite3_stmt
  -> CInt
  -- ^ Index
  -> IO (Ptr CUChar)

-- | Retrieves a column with a given index from the 'Statement'.
-- Assumes that 'step' was already called and that it returned
-- 'Row'.
column
  :: Statement
  -> Int
  -- ^ Index
  -> IO SQLData
column :: Statement -> Int -> IO SQLData
column (Statement ForeignPtr C'sqlite3_stmt
stFp Text
sSql Database
db) Int
intIdx =
  ForeignPtr C'sqlite3_stmt
-> (Ptr C'sqlite3_stmt -> IO SQLData) -> IO SQLData
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO SQLData) -> IO SQLData)
-> (Ptr C'sqlite3_stmt -> IO SQLData) -> IO SQLData
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
stPtr -> do
    CInt
idx <- Text -> Text -> Int -> IO CInt
intToCInt Text
sSql (Database -> Text
dbFilename Database
db) Int
intIdx
    CInt
colTypeNum <- Ptr C'sqlite3_stmt -> CInt -> IO CInt
sqlite3_column_type Ptr C'sqlite3_stmt
stPtr CInt
idx
    SQLData
colType <- case CInt -> Maybe SQLData
forall a. Integral a => a -> Maybe SQLData
Bindings.convertCColumnType CInt
colTypeNum of
      Just SQLData
n -> SQLData -> IO SQLData
forall (m :: * -> *) a. Monad m => a -> m a
return SQLData
n
      Maybe SQLData
Nothing -> Error -> IO SQLData
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO SQLData) -> Error -> IO SQLData
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
        { errorContext :: Text
errorContext = Text
sSql
        , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right (SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag)
-> SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. (a -> b) -> a -> b
$ CInt -> SqueatherErrorFlag
UnknownColumnType CInt
colTypeNum
        , errorText :: Text
errorText = Text
"Unknown column type found"
        , errorFilename :: Text
errorFilename = Database -> Text
dbFilename Database
db
        }
    case SQLData
colType of
      SQLData
SQLNull -> SQLData -> IO SQLData
forall (m :: * -> *) a. Monad m => a -> m a
return SQLData
SQLNull
      SQLFloat Double
_ -> (Double -> SQLData) -> IO Double -> IO SQLData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Double -> SQLData
SQLFloat (IO Double -> IO SQLData) -> IO Double -> IO SQLData
forall a b. (a -> b) -> a -> b
$ Ptr C'sqlite3_stmt -> CInt -> IO Double
sqlite3_column_double Ptr C'sqlite3_stmt
stPtr CInt
idx
      SQLBlob ByteString
_ -> do
        Ptr CChar
resPtr <- Ptr C'sqlite3_stmt -> CInt -> IO (Ptr CChar)
forall a. Ptr C'sqlite3_stmt -> CInt -> IO (Ptr a)
sqlite3_column_blob Ptr C'sqlite3_stmt
stPtr CInt
idx
        CInt
resLen <- Ptr C'sqlite3_stmt -> CInt -> IO CInt
sqlite3_column_bytes Ptr C'sqlite3_stmt
stPtr CInt
idx
        Int
resLenInt <- Text -> Text -> CInt -> IO Int
intFromCInt Text
sSql (Database -> Text
dbFilename Database
db) CInt
resLen
        ByteString
bs <- (Ptr CChar, Int) -> IO ByteString
ByteString.packCStringLen (Ptr CChar
resPtr, Int
resLenInt)
        SQLData -> IO SQLData
forall (m :: * -> *) a. Monad m => a -> m a
return (SQLData -> IO SQLData) -> SQLData -> IO SQLData
forall a b. (a -> b) -> a -> b
$ ByteString -> SQLData
SQLBlob ByteString
bs
      SQLInteger Int64
_ -> (Int64 -> SQLData) -> IO Int64 -> IO SQLData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int64 -> SQLData
SQLInteger (IO Int64 -> IO SQLData) -> IO Int64 -> IO SQLData
forall a b. (a -> b) -> a -> b
$ Ptr C'sqlite3_stmt -> CInt -> IO Int64
sqlite3_column_int64 Ptr C'sqlite3_stmt
stPtr CInt
idx
      SQLText Text
_ -> do
        Ptr CUChar
resPtr <- Ptr C'sqlite3_stmt -> CInt -> IO (Ptr CUChar)
sqlite3_column_text Ptr C'sqlite3_stmt
stPtr CInt
idx
        CInt
resLen <- Ptr C'sqlite3_stmt -> CInt -> IO CInt
sqlite3_column_bytes Ptr C'sqlite3_stmt
stPtr CInt
idx
        Int
resLenInt <- Text -> Text -> CInt -> IO Int
intFromCInt Text
sSql (Database -> Text
dbFilename Database
db) CInt
resLen
        ByteString
bs <- (Ptr CChar, Int) -> IO ByteString
ByteString.packCStringLen (Ptr CUChar -> Ptr CChar
forall a b. Ptr a -> Ptr b
Foreign.castPtr Ptr CUChar
resPtr, Int
resLenInt)
        SQLData -> IO SQLData
forall (m :: * -> *) a. Monad m => a -> m a
return (SQLData -> IO SQLData)
-> (ByteString -> SQLData) -> ByteString -> IO SQLData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> SQLData
SQLText (Text -> SQLData) -> (ByteString -> Text) -> ByteString -> SQLData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
Encoding.decodeUtf8 (ByteString -> IO SQLData) -> ByteString -> IO SQLData
forall a b. (a -> b) -> a -> b
$ ByteString
bs

-- | The number of columns that a given 'Statement' will return.
-- Works regardless of whether 'step' has been applied or not;
-- however, just because this returns a positive value does not mean
-- that 'step' will ever actually return a 'Row'.
columnCount :: Statement -> IO Int
columnCount :: Statement -> IO Int
columnCount (Statement ForeignPtr C'sqlite3_stmt
stFp Text
sSql Database
db)
  = ForeignPtr C'sqlite3_stmt
-> (Ptr C'sqlite3_stmt -> IO Int) -> IO Int
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO Int) -> IO Int)
-> (Ptr C'sqlite3_stmt -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
stPtr ->
  Ptr C'sqlite3_stmt -> IO CInt
sqlite3_column_count Ptr C'sqlite3_stmt
stPtr IO CInt -> (CInt -> IO Int) -> IO Int
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> Text -> CInt -> IO Int
intFromCInt Text
sSql (Database -> Text
dbFilename Database
db)

-- | Return all available columns, in order, from a 'Statement' on
-- which 'step' returned 'Row'.  You should already have applied
-- 'step'.
columns :: Statement -> IO [SQLData]
columns :: Statement -> IO [SQLData]
columns Statement
st = do
  Int
nCols <- Statement -> IO Int
columnCount Statement
st
  (Int -> IO SQLData) -> [Int] -> IO [SQLData]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Statement -> Int -> IO SQLData
column Statement
st) [Int
0 .. Int
nCols Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]

-- | Retrieves all remaining rows from a 'Statement'.  Applies
-- 'step' for you for as many times as needed.
allRows :: Statement -> IO [[SQLData]]
allRows :: Statement -> IO [[SQLData]]
allRows Statement
st = do
  StepResult
r <- Statement -> IO StepResult
step Statement
st
  case StepResult
r of
    StepResult
Types.Done -> [[SQLData]] -> IO [[SQLData]]
forall (m :: * -> *) a. Monad m => a -> m a
return []
    StepResult
Types.Row -> do
      [SQLData]
cols <- Statement -> IO [SQLData]
columns Statement
st
      [[SQLData]]
rest <- Statement -> IO [[SQLData]]
allRows Statement
st
      [[SQLData]] -> IO [[SQLData]]
forall (m :: * -> *) a. Monad m => a -> m a
return ([[SQLData]] -> IO [[SQLData]]) -> [[SQLData]] -> IO [[SQLData]]
forall a b. (a -> b) -> a -> b
$ [SQLData]
cols [SQLData] -> [[SQLData]] -> [[SQLData]]
forall a. a -> [a] -> [a]
: [[SQLData]]
rest

-- | Bind multiple named parameters to a 'Statement'.  
bindParams
  :: Statement
  -> [(Text, SQLData)]
  -> IO ()
bindParams :: Statement -> [(Text, SQLData)] -> IO ()
bindParams Statement
st = ((Text, SQLData) -> IO ()) -> [(Text, SQLData)] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ((Text -> SQLData -> IO ()) -> (Text, SQLData) -> IO ()
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (Statement -> Text -> SQLData -> IO ()
bindSqlData Statement
st))

-- | Execute a query without any parameters.  Executes only one
-- query - there is no need to terminate it with a semicolon,
-- although you can.  If you use a semicolon-separated list of
-- queries, only the first query will be run.  There is no way to
-- use SQL parameters; for that you will need 'executeNamed'.
execute
  :: Database
  -> Text
  -- ^ SQL text
  -> IO [[SQLData]]
  -- ^ All SQL data from the query.
execute :: Database -> Text -> IO [[SQLData]]
execute Database
db Text
sql = Database -> Text -> IO Statement
prepare Database
db Text
sql IO Statement -> (Statement -> IO [[SQLData]]) -> IO [[SQLData]]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Statement -> IO [[SQLData]]
allRows

-- | Execute a query with named parameters.  Executes only one
-- query - there is no need to terminate it with a semicolon,
-- although you can.  If you use a semicolon-separated list of
-- queries, only the first query will be run.
executeNamed
  :: Database
  -> Text
  -- ^ SQL text
  -> [(Text, SQLData)]
  -- ^ Pairs, where each 'Text' is a named parameter and each
  -- 'SQLData' is the corresponding data to bind to that parameter.
  -- [This page](https://www.sqlite.org/c3ref/bind_blob.html)
  -- describes the different parameter syntax that is allowed.
  -- Squeather makes no effort to support the plain @?@ syntax.  Note
  -- that the leading mark (@?@, @:@, @\@@, or @\$@) is part of the
  -- parameter name and must appear as part of the 'Text'.
  -> IO [[SQLData]]
  -- ^ All SQL data from the query.
executeNamed :: Database -> Text -> [(Text, SQLData)] -> IO [[SQLData]]
executeNamed Database
db Text
sql [(Text, SQLData)]
params = Database -> Text -> IO Statement
prepare Database
db Text
sql IO Statement -> (Statement -> IO [[SQLData]]) -> IO [[SQLData]]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Statement -> IO [[SQLData]]
use
  where
    use :: Statement -> IO [[SQLData]]
use Statement
stmt = do
      Statement -> [(Text, SQLData)] -> IO ()
bindParams Statement
stmt [(Text, SQLData)]
params
      Statement -> IO [[SQLData]]
allRows Statement
stmt

-- | Like 'executeNamed' but also returns the names of the columns
-- in addition to the SQL results.
executeNamedWithColumns
  :: Database
  -> Text
  -- ^ SQL text
  -> [(Text, SQLData)]
  -- ^ Pairs, where each 'Text' is a named parameter and each
  -- 'SQLData' is the corresponding data to bind to that parameter.
  -- [This page](https://www.sqlite.org/c3ref/bind_blob.html)
  -- describes the different parameter syntax that is allowed.
  -- Squeather makes no effort to support the plain @?@ syntax.  Note
  -- that the leading mark (@?@, @:@, @\@@, or @\$@) is part of the
  -- parameter name and must appear as part of the 'Text'.
  -> IO ([Text], [[SQLData]])
  -- ^ The column names, and all SQL data from the query.
executeNamedWithColumns :: Database -> Text -> [(Text, SQLData)] -> IO ([Text], [[SQLData]])
executeNamedWithColumns Database
db Text
sql [(Text, SQLData)]
params = Database -> Text -> IO Statement
prepare Database
db Text
sql IO Statement
-> (Statement -> IO ([Text], [[SQLData]]))
-> IO ([Text], [[SQLData]])
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Statement -> IO ([Text], [[SQLData]])
use
  where
    use :: Statement -> IO ([Text], [[SQLData]])
use Statement
stmt = do
      Statement -> [(Text, SQLData)] -> IO ()
bindParams Statement
stmt [(Text, SQLData)]
params
      [[SQLData]]
rows <- Statement -> IO [[SQLData]]
allRows Statement
stmt
      [Text]
names <- Statement -> IO [Text]
columnNames Statement
stmt
      ([Text], [[SQLData]]) -> IO ([Text], [[SQLData]])
forall (m :: * -> *) a. Monad m => a -> m a
return ([Text]
names, [[SQLData]]
rows)


-- | <https://www.sqlite.org/c3ref/reset.html>
foreign import ccall unsafe "sqlite3_reset" sqlite3_reset
  :: Ptr C'sqlite3_stmt
  -> IO CInt

-- | Resets a 'Statement' so it may be re-executed.  Does not clear
-- bindings.  In SQLite, 'sqlite3_reset' returns an error code if
-- the most recent step statement returned an error.  'reset' does
-- not do this.  It does not check the error code returned by
-- 'sqlite3_reset'.
reset :: Statement -> IO ()
reset :: Statement -> IO ()
reset (Statement ForeignPtr C'sqlite3_stmt
stFp Text
_ Database
_) = ForeignPtr C'sqlite3_stmt -> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO ()) -> IO ())
-> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
stPtr ->
  Ptr C'sqlite3_stmt -> IO CInt
sqlite3_reset Ptr C'sqlite3_stmt
stPtr IO CInt -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- | <https://www.sqlite.org/c3ref/clear_bindings.html>
foreign import ccall unsafe "sqlite3_clear_bindings" sqlite3_clear_bindings
  :: Ptr C'sqlite3_stmt
  -> IO CInt

-- | Clears all bindings on the 'Statement'.
clearBindings :: Statement -> IO ()
clearBindings :: Statement -> IO ()
clearBindings (Statement ForeignPtr C'sqlite3_stmt
stFp Text
_ Database
db)
  -- Checks the error code, but in SQLite version 3.31.1,
  -- sqlite3_clear_bindings will only ever return SQLITE_OK
  = ForeignPtr C'sqlite3_stmt -> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO ()) -> IO ())
-> (Ptr C'sqlite3_stmt -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
stPtr ->
  Ptr C'sqlite3_stmt -> IO CInt
sqlite3_clear_bindings Ptr C'sqlite3_stmt
stPtr IO CInt -> (CInt -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Database -> Text -> CInt -> IO ()
checkError Database
db Text
"clearing bindings"

foreign import ccall unsafe "sqlite3_finalize" sqlite3_finalize
  :: Ptr C'sqlite3_stmt
  -> IO CInt

foreign import ccall unsafe "&squeather_finalize" p_squeather_finalize
  :: FunPtr (Ptr C'sqlite3_stmt -> IO ())

-- | <https://www.sqlite.org/c3ref/close.html>
foreign import ccall unsafe "sqlite3_close_v2" sqlite3_close_v2
  :: Ptr C'sqlite3
  -> IO CInt

foreign import ccall unsafe "&squeather_close_v2" p_squeather_close_v2
  :: FunPtr (Ptr C'sqlite3 -> IO ())

-- | The type of the callback from 'sqlite3_exec'.  This callback is
-- invoked for every row of data.
type ExecCallback a
  = Ptr a
  -- ^ The fourth argument of 'sqlite3_exec' is passed through here.
  -> CInt
  -- ^ The number of columns in the result
  -> Ptr (Ptr CChar)
  -- ^ An array of pointers to strings obtained as if from
  -- @sqlite3_column_text@
  -> Ptr (Ptr CChar)
  -- ^ An array of pointers to strings where each entry represents
  -- the name of the corresponding result column as obtained from
  -- @sqlite3_column_name@
  -> IO CInt
  -- ^ The function should return zero if successful.  If it returns
  -- non-zero, then 'SQLITE_ABORT' will be thrown without involking
  -- the callback again and without running any more SQL statements.

-- | <https://www.sqlite.org/c3ref/exec.html>
foreign import ccall "sqlite3_exec" sqlite3_exec
  :: Ptr C'sqlite3
  -> Ptr CChar
  -- ^ SQL
  -> FunPtr (ExecCallback a)
  -- ^ Callback.  Pass 'Foreign.nullFunPtr' if you do not with to use
  -- a callback.
  -> Ptr a
  -- ^ Passed to callback for every row
  -> Ptr (Ptr CChar)
  -- ^ If there is a failure, the error message is written here.  If
  -- there is no failure, 'Foreign.nullPtr' is written here.
  -> IO CInt

-- | <https://www.sqlite.org/c3ref/free.html>
foreign import ccall unsafe "sqlite3_free" sqlite3_free
  :: Ptr a
  -> IO ()

-- | Evaluate one or more SQL statements.  There is no way to obtain
-- the results; for that you will need 'execute' or 'executeNamed'.
-- There is no way to use SQL parameters; for that you will need
-- 'executeNamed'.
exec
  :: Database
  -> Text
  -- ^ SQL to be evaluated.  Multiple, semicolon-separated
  -- statements will be executed.
  -> IO ()
exec :: Database -> Text -> IO ()
exec db :: Database
db@(Database ForeignPtr C'sqlite3
dbFp Text
dbFn) Text
sqlTxt =
  Text -> (Ptr CChar -> IO ()) -> IO ()
forall a. Text -> (Ptr CChar -> IO a) -> IO a
writeUtf8 Text
sqlTxt ((Ptr CChar -> IO ()) -> IO ()) -> (Ptr CChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
ptrSql ->
  ForeignPtr C'sqlite3 -> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3
dbFp ((Ptr C'sqlite3 -> IO ()) -> IO ())
-> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3
dbPtr ->
  (Ptr (Ptr CChar) -> IO ()) -> IO ()
forall a b. Storable a => (Ptr a -> IO b) -> IO b
Foreign.alloca ((Ptr (Ptr CChar) -> IO ()) -> IO ())
-> (Ptr (Ptr CChar) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr (Ptr CChar)
strErr -> do
    Ptr (Ptr CChar) -> Ptr CChar -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
Foreign.poke Ptr (Ptr CChar)
strErr Ptr CChar
forall a. Ptr a
Foreign.nullPtr
    let cleanup :: IO ()
cleanup = Ptr (Ptr CChar) -> IO (Ptr CChar)
forall a. Storable a => Ptr a -> IO a
Foreign.peek Ptr (Ptr CChar)
strErr IO (Ptr CChar) -> (Ptr CChar -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Ptr CChar -> IO ()
forall a. Ptr a -> IO ()
sqlite3_free
        runExec :: IO ()
runExec = do
          CInt
code <- Ptr C'sqlite3
-> Ptr CChar
-> FunPtr (ExecCallback Any)
-> Ptr Any
-> Ptr (Ptr CChar)
-> IO CInt
forall a.
Ptr C'sqlite3
-> Ptr CChar
-> FunPtr (ExecCallback a)
-> Ptr a
-> Ptr (Ptr CChar)
-> IO CInt
sqlite3_exec Ptr C'sqlite3
dbPtr Ptr CChar
ptrSql FunPtr (ExecCallback Any)
forall b. FunPtr b
Foreign.nullFunPtr Ptr Any
forall a. Ptr a
Foreign.nullPtr Ptr (Ptr CChar)
strErr
          Ptr CChar
errVal <- Ptr (Ptr CChar) -> IO (Ptr CChar)
forall a. Storable a => Ptr a -> IO a
Foreign.peek Ptr (Ptr CChar)
strErr
          Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Ptr CChar
errVal Ptr CChar -> Ptr CChar -> Bool
forall a. Eq a => a -> a -> Bool
/= Ptr CChar
forall a. Ptr a
Foreign.nullPtr) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
            Text
errTxt <- Ptr CChar -> IO Text
readUtf8 Ptr CChar
errVal
            Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error Text
sqlTxt (SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right SqueatherErrorFlag
ExecFailed) Text
errTxt Text
dbFn
          Database -> Text -> CInt -> IO ()
checkError Database
db Text
sqlTxt CInt
code
    IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO a
Exception.finally IO ()
runExec IO ()
cleanup

-- | <https://www.sqlite.org/c3ref/last_insert_rowid.html>
foreign import ccall unsafe "sqlite3_last_insert_rowid" sqlite3_last_insert_rowid
  :: Ptr C'sqlite3
  -> IO Int64

-- | Get the rowid of the most recent successful INSERT.
lastInsertRowId :: Database -> IO Int64
lastInsertRowId :: Database -> IO Int64
lastInsertRowId (Database ForeignPtr C'sqlite3
dbFp Text
_) =
  ForeignPtr C'sqlite3 -> (Ptr C'sqlite3 -> IO Int64) -> IO Int64
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3
dbFp Ptr C'sqlite3 -> IO Int64
sqlite3_last_insert_rowid

-- | Convert from an Int to a CInt.  Makes sure the conversion fits
-- in the space allotted.  Throws an exception if it doesn't fit.
intToCInt
  :: Text
  -- ^ Context.  For error messages only.
  -> Text
  -- ^ Database filename.  For error messages only.
  -> Int
  -> IO CInt
intToCInt :: Text -> Text -> Int -> IO CInt
intToCInt Text
ctx Text
fn Int
i
  | Integer
iConv Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> CInt -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt
forall a. Bounded a => a
maxBound :: CInt)
      = Text -> IO CInt
forall a. Text -> IO a
throw (Text -> IO CInt) -> (String -> Text) -> String -> IO CInt
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> IO CInt) -> String -> IO CInt
forall a b. (a -> b) -> a -> b
$ String
"number too big to convert to CInt: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
i
  | Integer
iConv Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< CInt -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt
forall a. Bounded a => a
minBound :: CInt)
      = Text -> IO CInt
forall a. Text -> IO a
throw (Text -> IO CInt) -> (String -> Text) -> String -> IO CInt
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> IO CInt) -> String -> IO CInt
forall a b. (a -> b) -> a -> b
$ String
"number too small to convert to CInt: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
i
  | Bool
otherwise = CInt -> IO CInt
forall (m :: * -> *) a. Monad m => a -> m a
return (CInt -> IO CInt) -> CInt -> IO CInt
forall a b. (a -> b) -> a -> b
$ Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i
  where
    iConv :: Integer
iConv = Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i :: Integer
    throw :: Text -> IO a
throw Text
str = Error -> IO a
forall e a. Exception e => e -> IO a
Exception.throwIO Error
exc
      where
        exc :: Error
exc = Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error { errorContext :: Text
errorContext = Text
ctx
                    , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right SqueatherErrorFlag
IntConversion
                    , errorText :: Text
errorText = Text
str
                    , errorFilename :: Text
errorFilename = Text
fn
                    }

-- | Convert from an CInt to a Int.  Makes sure the conversion fits
-- in the space allotted.  Throws an exception if it doesn't fit.
intFromCInt
  :: Text
  -- ^ Context.  For error messages only.
  -> Text
  -- ^ Database filename.  For error messages only.
  -> CInt
  -> IO Int
intFromCInt :: Text -> Text -> CInt -> IO Int
intFromCInt Text
ctx Text
fn CInt
i
  | Integer
iConv Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
forall a. Bounded a => a
maxBound :: Int)
    = Text -> IO Int
forall a. Text -> IO a
throw (Text -> IO Int) -> (String -> Text) -> String -> IO Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> IO Int) -> String -> IO Int
forall a b. (a -> b) -> a -> b
$ String
"number too big to convert to Int: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ CInt -> String
forall a. Show a => a -> String
show CInt
i
  | Integer
iConv Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
forall a. Bounded a => a
minBound :: Int)
    = Text -> IO Int
forall a. Text -> IO a
throw (Text -> IO Int) -> (String -> Text) -> String -> IO Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> IO Int) -> String -> IO Int
forall a b. (a -> b) -> a -> b
$ String
"number too small to convert to Int: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ CInt -> String
forall a. Show a => a -> String
show CInt
i
  | Bool
otherwise = Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> IO Int) -> Int -> IO Int
forall a b. (a -> b) -> a -> b
$ CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
i
  where
    iConv :: Integer
iConv = CInt -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
i :: Integer
    throw :: Text -> IO a
throw Text
str = Error -> IO a
forall e a. Exception e => e -> IO a
Exception.throwIO Error
exc
      where
        exc :: Error
exc = Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error { errorContext :: Text
errorContext = Text
ctx
                    , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right SqueatherErrorFlag
IntConversion
                    , errorText :: Text
errorText = Text
str
                    , errorFilename :: Text
errorFilename = Text
fn
                    }


-- | Returns a string which is the version number for SQLite used to
-- build this library.  SQLite is embedded into the library, so the
-- only way to change the SQLite version is to recompile the
-- library.
sqliteVersion :: String
sqliteVersion :: String
sqliteVersion = String
Bindings.c'SQLITE_VERSION

-- | Default settings for 'OpenFlags', where the 'Types.writeMode'
-- is 'Types.ReadWrite' 'Types.Create', 'Types.threadMode' is
-- 'Types.Serialized', 'Types.cacheMode' is 'Types.Private', and all
-- other flags are set to False.
openFlags :: OpenFlags
openFlags :: OpenFlags
openFlags = OpenFlags :: WriteMode
-> Bool -> Bool -> ThreadMode -> CacheMode -> Bool -> OpenFlags
Types.OpenFlags
  { writeMode :: WriteMode
Types.writeMode = Create -> WriteMode
Types.ReadWrite Create
Types.Create
  , uri :: Bool
Types.uri = Bool
False
  , memory :: Bool
Types.memory = Bool
False
  , threadMode :: ThreadMode
Types.threadMode = ThreadMode
Types.Serialized
  , cacheMode :: CacheMode
Types.cacheMode = CacheMode
Types.Private
  , noFollow :: Bool
Types.noFollow = Bool
False
  }

-- Backup API

data C'sqlite3_backup

-- | <https://www.sqlite.org/c3ref/backup_finish.html>
foreign import ccall unsafe "sqlite3_backup_init" sqlite3_backup_init
  :: Ptr C'sqlite3
  -- ^ Destination database handle
  -> Ptr CChar
  -- ^ Destination database name - @main@ for the main database,
  -- @temp@ for the temporary database, or the name specified after
  -- the @AS@ keyword in an @ATTACH@ statement for an attached
  -- database.
  -> Ptr C'sqlite3
  -- ^ Source database handle
  -> Ptr CChar
  -- ^ Source database name
  -> IO (Ptr C'sqlite3_backup)
  -- ^ Returns pointer to backup object

-- | <https://www.sqlite.org/c3ref/backup_finish.html>
foreign import ccall unsafe "sqlite3_backup_step" sqlite3_backup_step
  :: Ptr C'sqlite3_backup
  -> CInt
  -- ^ Number of pages.  If negative, copy all remaining source
  -- pages.
  -> IO CInt
  -- ^ Returns error code

-- | <https://www.sqlite.org/c3ref/backup_finish.html>
foreign import ccall unsafe "sqlite3_backup_finish" sqlite3_backup_finish
  :: Ptr C'sqlite3_backup
  -> IO CInt
  -- ^ Returns error code

-- | <https://www.sqlite.org/c3ref/backup_finish.html>
foreign import ccall unsafe "sqlite3_backup_remaining" sqlite3_backup_remaining
  :: Ptr C'sqlite3_backup
  -> IO CInt
  -- ^ Returns number of pages remaining to be backed up

-- | <https://www.sqlite.org/c3ref/backup_finish.html>
foreign import ccall unsafe "sqlite3_backup_pagecount" sqlite3_backup_pagecount
  :: Ptr C'sqlite3_backup
  -> IO CInt
  -- ^ Returns number of pages in source database

-- | Backup source
data Source = Source
  { Source -> Database
sourceConnection :: Database
  , Source -> Text
sourceName :: Text
  -- ^ The name for the source database.  Use @main@ for the
  -- main database, @temp@ for the temporary database, or the name
  -- specified after the @AS@ keyword in an @ATTACH@ statement for
  -- an attached database.
  } deriving (Source -> Source -> Bool
(Source -> Source -> Bool)
-> (Source -> Source -> Bool) -> Eq Source
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Source -> Source -> Bool
$c/= :: Source -> Source -> Bool
== :: Source -> Source -> Bool
$c== :: Source -> Source -> Bool
Eq, Eq Source
Eq Source
-> (Source -> Source -> Ordering)
-> (Source -> Source -> Bool)
-> (Source -> Source -> Bool)
-> (Source -> Source -> Bool)
-> (Source -> Source -> Bool)
-> (Source -> Source -> Source)
-> (Source -> Source -> Source)
-> Ord Source
Source -> Source -> Bool
Source -> Source -> Ordering
Source -> Source -> Source
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Source -> Source -> Source
$cmin :: Source -> Source -> Source
max :: Source -> Source -> Source
$cmax :: Source -> Source -> Source
>= :: Source -> Source -> Bool
$c>= :: Source -> Source -> Bool
> :: Source -> Source -> Bool
$c> :: Source -> Source -> Bool
<= :: Source -> Source -> Bool
$c<= :: Source -> Source -> Bool
< :: Source -> Source -> Bool
$c< :: Source -> Source -> Bool
compare :: Source -> Source -> Ordering
$ccompare :: Source -> Source -> Ordering
$cp1Ord :: Eq Source
Ord, Int -> Source -> ShowS
[Source] -> ShowS
Source -> String
(Int -> Source -> ShowS)
-> (Source -> String) -> ([Source] -> ShowS) -> Show Source
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Source] -> ShowS
$cshowList :: [Source] -> ShowS
show :: Source -> String
$cshow :: Source -> String
showsPrec :: Int -> Source -> ShowS
$cshowsPrec :: Int -> Source -> ShowS
Show)

-- | Backup destination
data Destination = Destination
  { Destination -> Database
destConnection :: Database
  , Destination -> Text
destName :: Text
  -- ^ The name for the destination database.  Use @main@ for the
  -- main database, @temp@ for the temporary database, or the name
  -- specified after the @AS@ keyword in an @ATTACH@ statement for
  -- an attached database.
  } deriving (Destination -> Destination -> Bool
(Destination -> Destination -> Bool)
-> (Destination -> Destination -> Bool) -> Eq Destination
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Destination -> Destination -> Bool
$c/= :: Destination -> Destination -> Bool
== :: Destination -> Destination -> Bool
$c== :: Destination -> Destination -> Bool
Eq, Eq Destination
Eq Destination
-> (Destination -> Destination -> Ordering)
-> (Destination -> Destination -> Bool)
-> (Destination -> Destination -> Bool)
-> (Destination -> Destination -> Bool)
-> (Destination -> Destination -> Bool)
-> (Destination -> Destination -> Destination)
-> (Destination -> Destination -> Destination)
-> Ord Destination
Destination -> Destination -> Bool
Destination -> Destination -> Ordering
Destination -> Destination -> Destination
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Destination -> Destination -> Destination
$cmin :: Destination -> Destination -> Destination
max :: Destination -> Destination -> Destination
$cmax :: Destination -> Destination -> Destination
>= :: Destination -> Destination -> Bool
$c>= :: Destination -> Destination -> Bool
> :: Destination -> Destination -> Bool
$c> :: Destination -> Destination -> Bool
<= :: Destination -> Destination -> Bool
$c<= :: Destination -> Destination -> Bool
< :: Destination -> Destination -> Bool
$c< :: Destination -> Destination -> Bool
compare :: Destination -> Destination -> Ordering
$ccompare :: Destination -> Destination -> Ordering
$cp1Ord :: Eq Destination
Ord, Int -> Destination -> ShowS
[Destination] -> ShowS
Destination -> String
(Int -> Destination -> ShowS)
-> (Destination -> String)
-> ([Destination] -> ShowS)
-> Show Destination
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Destination] -> ShowS
$cshowList :: [Destination] -> ShowS
show :: Destination -> String
$cshow :: Destination -> String
showsPrec :: Int -> Destination -> ShowS
$cshowsPrec :: Int -> Destination -> ShowS
Show)

-- | Use the SQLite backup API to copy the content of one database
-- to another.  Can be used to safely copy databases while they are
-- in use, or to copy in-memory databases to or from persistent
-- files.
backup :: Source -> Destination -> IO ()
backup :: Source -> Destination -> IO ()
backup Source
src Destination
dest =
  ForeignPtr C'sqlite3 -> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr (Database -> ForeignPtr C'sqlite3
dbPointer (Database -> ForeignPtr C'sqlite3)
-> (Destination -> Database) -> Destination -> ForeignPtr C'sqlite3
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Destination -> Database
destConnection (Destination -> ForeignPtr C'sqlite3)
-> Destination -> ForeignPtr C'sqlite3
forall a b. (a -> b) -> a -> b
$ Destination
dest) ((Ptr C'sqlite3 -> IO ()) -> IO ())
-> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3
ptrDestDb ->
  ForeignPtr C'sqlite3 -> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr (Database -> ForeignPtr C'sqlite3
dbPointer (Database -> ForeignPtr C'sqlite3)
-> (Source -> Database) -> Source -> ForeignPtr C'sqlite3
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Source -> Database
sourceConnection (Source -> ForeignPtr C'sqlite3) -> Source -> ForeignPtr C'sqlite3
forall a b. (a -> b) -> a -> b
$ Source
src) ((Ptr C'sqlite3 -> IO ()) -> IO ())
-> (Ptr C'sqlite3 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3
ptrSrcDb ->
  Text -> (Ptr CChar -> IO ()) -> IO ()
forall a. Text -> (Ptr CChar -> IO a) -> IO a
writeUtf8 (Source -> Text
sourceName Source
src) ((Ptr CChar -> IO ()) -> IO ()) -> (Ptr CChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
ptrSrcName ->
  Text -> (Ptr CChar -> IO ()) -> IO ()
forall a. Text -> (Ptr CChar -> IO a) -> IO a
writeUtf8 (Destination -> Text
destName Destination
dest) ((Ptr CChar -> IO ()) -> IO ()) -> (Ptr CChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
ptrDestName ->
  let
    acq :: IO (Ptr C'sqlite3_backup)
acq = Ptr C'sqlite3
-> Ptr CChar
-> Ptr C'sqlite3
-> Ptr CChar
-> IO (Ptr C'sqlite3_backup)
sqlite3_backup_init Ptr C'sqlite3
ptrDestDb Ptr CChar
ptrDestName Ptr C'sqlite3
ptrSrcDb Ptr CChar
ptrSrcName
    rel :: Ptr C'sqlite3_backup -> IO CInt
rel = Ptr C'sqlite3_backup -> IO CInt
sqlite3_backup_finish
    use :: Ptr C'sqlite3_backup -> IO ()
use Ptr C'sqlite3_backup
bkpPtr = do
      CInt
code <- Ptr C'sqlite3_backup -> CInt -> IO CInt
sqlite3_backup_step Ptr C'sqlite3_backup
bkpPtr (-CInt
1)
      case CInt -> ParseErrorResult
forall a. (Integral a, Show a) => a -> ParseErrorResult
Bindings.parseError CInt
code of
        Bindings.ParseErrorStep StepResult
Types.Done -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        ParseErrorResult
Bindings.ParseErrorOk -> Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
          { errorContext :: Text
errorContext = Text
ctx
          , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right SqueatherErrorFlag
IncompleteBackup
          , errorText :: Text
errorText = Text
"Squeather.backup: backup did not complete"
          , errorFilename :: Text
errorFilename = Text
ctx
          }
        Bindings.ParseErrorStep StepResult
Types.Row -> Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
          { errorContext :: Text
errorContext = Text
ctx
          , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right SqueatherErrorFlag
Bug
          , errorText :: Text
errorText = Text
"Squeather.backup: returned Row StepResult - should never happen"
          , errorFilename :: Text
errorFilename = Text
ctx
          }
        Bindings.ParseErrorError ErrorFlag
flg -> Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
          { errorContext :: Text
errorContext = Text
ctx
          , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = ErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. a -> Either a b
Left ErrorFlag
flg
          , errorText :: Text
errorText = Text
"Squeather.backup: error during backup"
          , errorFilename :: Text
errorFilename = Text
ctx
          }
        ParseErrorResult
Bindings.ParseErrorNotFound -> Error -> IO ()
forall e a. Exception e => e -> IO a
Exception.throwIO (Error -> IO ()) -> Error -> IO ()
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
          { errorContext :: Text
errorContext = Text
ctx
          , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right (SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag)
-> SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. (a -> b) -> a -> b
$ CInt -> SqueatherErrorFlag
UnknownSqliteError CInt
code
          , errorText :: Text
errorText = Text
"Squeather.backup: error during backup - code not found"
          , errorFilename :: Text
errorFilename = Text
ctx
          }
    ctx :: Text
ctx = Text
"during backup from " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Database -> Text
dbFilename (Source -> Database
sourceConnection Source
src) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" to "
      Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Database -> Text
dbFilename (Destination -> Database
destConnection Destination
dest)

  in IO (Ptr C'sqlite3_backup)
-> (Ptr C'sqlite3_backup -> IO CInt)
-> (Ptr C'sqlite3_backup -> IO ())
-> IO ()
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
Exception.bracket IO (Ptr C'sqlite3_backup)
acq Ptr C'sqlite3_backup -> IO CInt
rel Ptr C'sqlite3_backup -> IO ()
use

-- | <https://www.sqlite.org/c3ref/changes.html>
foreign import ccall unsafe "sqlite3_changes" sqlite3_changes
  :: Ptr C'sqlite3
  -> IO CInt

-- | Count the number of rows modified by the most recent @INSERT@,
-- @UPDATE@, or @DELETE@ statement.
changes :: Database -> IO Int
changes :: Database -> IO Int
changes (Database ForeignPtr C'sqlite3
dbFp Text
dbName) =
  ForeignPtr C'sqlite3 -> (Ptr C'sqlite3 -> IO Int) -> IO Int
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3
dbFp ((Ptr C'sqlite3 -> IO Int) -> IO Int)
-> (Ptr C'sqlite3 -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3
dbPtr ->
  Ptr C'sqlite3 -> IO CInt
sqlite3_changes Ptr C'sqlite3
dbPtr IO CInt -> (CInt -> IO Int) -> IO Int
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> Text -> CInt -> IO Int
intFromCInt Text
"changes" Text
dbName

-- Column names

foreign import ccall unsafe "sqlite3_column_name" sqlite3_column_name
  :: Ptr C'sqlite3_stmt
  -> CInt
  -> IO (Ptr CChar)

-- | Gets the name of a column.  The name is the value of the @AS@
-- clause if it exists, or is an undefined string otherwise.
columnName
  :: Statement
  -> Int
  -- ^ Index.  The leftmost column is @0@.
  -> IO Text
columnName :: Statement -> Int -> IO Text
columnName (Statement ForeignPtr C'sqlite3_stmt
stFp Text
stSql Database
db) Int
idx =
  ForeignPtr C'sqlite3_stmt
-> (Ptr C'sqlite3_stmt -> IO Text) -> IO Text
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
Foreign.withForeignPtr ForeignPtr C'sqlite3_stmt
stFp ((Ptr C'sqlite3_stmt -> IO Text) -> IO Text)
-> (Ptr C'sqlite3_stmt -> IO Text) -> IO Text
forall a b. (a -> b) -> a -> b
$ \Ptr C'sqlite3_stmt
stPtr -> do
    CInt
cIntIdx <- Text -> Text -> Int -> IO CInt
intToCInt (Text
"getting column name in " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
stSql) (Database -> Text
dbFilename Database
db) Int
idx
    Ptr CChar
ptrStr <- Ptr C'sqlite3_stmt -> CInt -> IO (Ptr CChar)
sqlite3_column_name Ptr C'sqlite3_stmt
stPtr CInt
cIntIdx
    if Ptr CChar
ptrStr Ptr CChar -> Ptr CChar -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr CChar
forall a. Ptr a
Foreign.nullPtr
      then Error -> IO Text
forall e a. Exception e => e -> IO a
throwIO (Error -> IO Text) -> Error -> IO Text
forall a b. (a -> b) -> a -> b
$ Error :: Text
-> Either ErrorFlag SqueatherErrorFlag -> Text -> Text -> Error
Error
            { errorContext :: Text
errorContext = Text
stSql
            , errorFlag :: Either ErrorFlag SqueatherErrorFlag
errorFlag = SqueatherErrorFlag -> Either ErrorFlag SqueatherErrorFlag
forall a b. b -> Either a b
Right (Int -> SqueatherErrorFlag
ColumnNameNull Int
idx)
            , errorText :: Text
errorText = String -> Text
Text.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
"null pointer returned when getting column name for index " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
idx
            , errorFilename :: Text
errorFilename = Database -> Text
dbFilename Database
db
            }
      else Ptr CChar -> IO Text
readUtf8 Ptr CChar
ptrStr

-- | Gets all column names, in order.
columnNames :: Statement -> IO [Text]
columnNames :: Statement -> IO [Text]
columnNames Statement
stmt = do
  Int
i <- Statement -> IO Int
columnCount Statement
stmt
  (Int -> IO Text) -> [Int] -> IO [Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Statement -> Int -> IO Text
columnName Statement
stmt) [Int
0 .. (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)]

-- | Returns zero if mutexing code was omitted.
foreign import ccall unsafe "sqlite3_threadsafe" sqlite3_threadsafe
  :: IO CInt

-- | Initialize the SQLite library, see
--
-- <https://www.sqlite.org/c3ref/initialize.html>
foreign import ccall unsafe "sqlite3_initialize" sqlite3_initialize
  :: IO CInt