diff --git a/Database/SQLite3.hs b/Database/SQLite3.hs
--- a/Database/SQLite3.hs
+++ b/Database/SQLite3.hs
@@ -8,7 +8,7 @@
     close,
 
     -- * Simple query execution
-    -- | <http://sqlite.org/c3ref/exec.html>
+    -- | <https://sqlite.org/c3ref/exec.html>
     exec,
     execPrint,
     execWithCallback,
@@ -18,6 +18,7 @@
     prepare,
     prepareUtf8,
     step,
+    stepNoCB,
     reset,
     finalize,
     clearBindings,
@@ -29,7 +30,7 @@
     columnName,
 
     -- * Binding values to a prepared statement
-    -- | <http://www.sqlite.org/c3ref/bind_blob.html>
+    -- | <https://www.sqlite.org/c3ref/bind_blob.html>
     bindSQLData,
     bind,
     bindNamed,
@@ -42,7 +43,7 @@
     bindNull,
 
     -- * Reading the result row
-    -- | <http://www.sqlite.org/c3ref/column_blob.html>
+    -- | <https://www.sqlite.org/c3ref/column_blob.html>
     --
     -- Warning: 'column' and 'columns' will throw a 'DecodeError' if any @TEXT@
     -- datum contains invalid UTF-8.
@@ -182,7 +183,6 @@
 import Prelude hiding (error)
 import qualified Data.Text as T
 import qualified Data.Text.IO as T
-import Control.Applicative  ((<$>))
 import Control.Concurrent
 import Control.Exception
 import Control.Monad        (when, zipWithM, zipWithM_)
@@ -221,7 +221,6 @@
 -- to defer message construction in the case where a user catches and
 -- immediately handles the error.
 
-
 instance Show SQLError where
     show SQLError{ sqlError        = code
                  , sqlErrorDetails = details
@@ -285,14 +284,13 @@
 appendShow :: Show a => Text -> a -> Text
 appendShow txt a = txt `T.append` (T.pack . show) a
 
-
--- | <http://www.sqlite.org/c3ref/open.html>
+-- | <https://www.sqlite.org/c3ref/open.html>
 open :: Text -> IO Database
 open path =
     Direct.open (toUtf8 path)
         >>= checkErrorMsg ("open " `appendShow` path)
 
--- | <http://www.sqlite.org/c3ref/close.html>
+-- | <https://www.sqlite.org/c3ref/close.html>
 close :: Database -> IO ()
 close db =
     Direct.close db >>= checkError (DetailDatabase db) "close"
@@ -383,7 +381,7 @@
     -> [Maybe Text]   -- ^ List of column values, as returned by 'columnText'.
     -> IO ()
 
--- | <http://www.sqlite.org/c3ref/prepare.html>
+-- | <https://www.sqlite.org/c3ref/prepare.html>
 --
 -- Unlike 'exec', 'prepare' only executes the first statement, and ignores
 -- subsequent statements.
@@ -392,7 +390,7 @@
 prepare :: Database -> Text -> IO Statement
 prepare db sql = prepareUtf8 db (toUtf8 sql)
 
--- | <http://www.sqlite.org/c3ref/prepare.html>
+-- | <https://www.sqlite.org/c3ref/prepare.html>
 --
 -- It can help to avoid redundant Utf8 to Text conversion if you already
 -- have Utf8
@@ -406,11 +404,19 @@
         Nothing   -> fail "Direct.SQLite3.prepare: empty query string"
         Just stmt -> return stmt
 
--- | <http://www.sqlite.org/c3ref/step.html>
+-- | <https://www.sqlite.org/c3ref/step.html>
 step :: Statement -> IO StepResult
 step statement =
     Direct.step statement >>= checkError (DetailStatement statement) "step"
 
+-- | <https://www.sqlite.org/c3ref/step.html>
+--
+-- Faster step for statements that don't callback to Haskell
+-- functions (e.g. by using custom SQL functions).
+stepNoCB :: Statement -> IO StepResult
+stepNoCB statement =
+    Direct.stepNoCB statement >>= checkError (DetailStatement statement) "stepNoCB"
+
 -- Note: sqlite3_reset and sqlite3_finalize return an error code if the most
 -- recent sqlite3_step indicated an error.  I think these are the only times
 -- these functions return an error (barring memory corruption and misuse of the API).
@@ -431,7 +437,7 @@
 --
 --  [1]: https://github.com/yesodweb/persistent/issues/92#issuecomment-7806421
 
--- | <http://www.sqlite.org/c3ref/reset.html>
+-- | <https://www.sqlite.org/c3ref/reset.html>
 --
 -- Note that in the C API, @sqlite3_reset@ returns an error code if the most
 -- recent @sqlite3_step@ indicated an error.  We do not replicate that behavior
@@ -441,7 +447,7 @@
     _ <- Direct.reset statement
     return ()
 
--- | <http://www.sqlite.org/c3ref/finalize.html>
+-- | <https://www.sqlite.org/c3ref/finalize.html>
 --
 -- Like 'reset', 'finalize' never throws an exception.
 finalize :: Statement -> IO ()
@@ -449,8 +455,7 @@
     _ <- Direct.finalize statement
     return ()
 
-
--- | <http://www.sqlite.org/c3ref/bind_parameter_name.html>
+-- | <https://www.sqlite.org/c3ref/bind_parameter_name.html>
 --
 -- Return the N-th SQL parameter name.
 --
@@ -468,7 +473,7 @@
   where
     desc = "Database.SQLite3.bindParameterName: Invalid UTF-8"
 
--- | <http://www.sqlite.org/c3ref/column_name.html>
+-- | <https://www.sqlite.org/c3ref/column_name.html>
 --
 -- Return the name of a result column.  If the column index is out of range,
 -- return 'Nothing'.
@@ -587,9 +592,7 @@
                 Nothing ->
                     fail ("unknown named parameter "++show name)
 
-
--- |
--- This will throw a 'DecodeError' if the datum contains invalid UTF-8.
+-- | This will throw a 'DecodeError' if the datum contains invalid UTF-8.
 -- If this behavior is undesirable, you can use 'Direct.columnText' from
 -- "Database.SQLite3.Direct", which does not perform conversion to 'Text'.
 columnText :: Statement -> ColumnIndex -> IO Text
@@ -615,10 +618,9 @@
     BlobColumn    -> SQLBlob    <$> columnBlob   statement idx
     NullColumn    -> return SQLNull
 
--- |
--- This avoids extra API calls using the list of column types.
+-- | This avoids extra API calls using the list of column types.
 -- If passed types do not correspond to the actual types, the values will be
--- converted according to the rules at <http://www.sqlite.org/c3ref/column_blob.html>.
+-- converted according to the rules at <https://www.sqlite.org/c3ref/column_blob.html>.
 -- If the list contains more items that number of columns, the result is undefined.
 typedColumns :: Statement -> [Maybe ColumnType] -> IO [SQLData]
 typedColumns statement = zipWithM f [0..] where
@@ -626,8 +628,7 @@
         Nothing -> column statement idx
         Just t  -> typedColumn t statement idx
 
-
--- | <http://sqlite.org/c3ref/create_function.html>
+-- | <https://sqlite.org/c3ref/create_function.html>
 --
 -- Create a custom SQL function or redefine the behavior of an existing
 -- function. If the function is deterministic, i.e. if it always returns the
@@ -687,8 +688,7 @@
 funcResultText ctx value =
     Direct.funcResultText ctx (toUtf8 value)
 
-
--- | <http://www.sqlite.org/c3ref/create_collation.html>
+-- | <https://www.sqlite.org/c3ref/create_collation.html>
 createCollation
     :: Database
     -> Text                       -- ^ Name of the collation.
@@ -708,7 +708,6 @@
     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.
@@ -731,7 +730,10 @@
         >>= checkError (DetailDatabase db) "blobClose"
 
 -- | <https://www.sqlite.org/c3ref/blob_reopen.html>
-blobReopen :: Blob -> Int64 -> IO ()
+blobReopen
+    :: Blob
+    -> Int64 -- ^ The @ROWID@ of the row.
+    -> IO ()
 blobReopen blob@(Direct.Blob db _) rowid =
     Direct.blobReopen blob rowid
         >>= checkError (DetailDatabase db) "blobReopen"
@@ -761,18 +763,17 @@
     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
+    :: 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 -> IO ()
 backupFinish backup@(Direct.Backup dstDb _) =
     Direct.backupFinish backup
         >>= checkError (DetailDatabase dstDb) "backupFinish"
diff --git a/Database/SQLite3/Bindings.hs b/Database/SQLite3/Bindings.hs
--- a/Database/SQLite3/Bindings.hs
+++ b/Database/SQLite3/Bindings.hs
@@ -15,7 +15,7 @@
     c_sqlite3_enable_shared_cache,
 
     -- * Simple query execution
-    -- | <http://sqlite.org/c3ref/exec.html>
+    -- | <https://sqlite.org/c3ref/exec.html>
     c_sqlite3_exec,
     CExecCallback,
     mkCExecCallback,
@@ -24,6 +24,7 @@
     c_sqlite3_prepare_v2,
     c_sqlite3_db_handle,
     c_sqlite3_step,
+    c_sqlite3_step_unsafe,
     c_sqlite3_reset,
     c_sqlite3_finalize,
     c_sqlite3_clear_bindings,
@@ -37,7 +38,7 @@
     c_sqlite3_column_name,
 
     -- * Binding Values To Prepared Statements
-    -- | <http://www.sqlite.org/c3ref/bind_blob.html>
+    -- | <https://www.sqlite.org/c3ref/bind_blob.html>
     c_sqlite3_bind_blob,
     c_sqlite3_bind_zeroblob,
     c_sqlite3_bind_text,
@@ -46,7 +47,7 @@
     c_sqlite3_bind_null,
 
     -- * Result Values From A Query
-    -- | <http://www.sqlite.org/c3ref/column_blob.html>
+    -- | <https://www.sqlite.org/c3ref/column_blob.html>
     c_sqlite3_column_type,
     c_sqlite3_column_bytes,
     c_sqlite3_column_blob,
@@ -72,7 +73,7 @@
     c_sqlite3_aggregate_context,
 
     -- * Obtaining SQL Function Parameter Values
-    -- | <http://www.sqlite.org/c3ref/value_blob.html>
+    -- | <https://www.sqlite.org/c3ref/value_blob.html>
     c_sqlite3_value_type,
     c_sqlite3_value_bytes,
     c_sqlite3_value_blob,
@@ -81,7 +82,7 @@
     c_sqlite3_value_double,
 
     -- * Setting The Result Of An SQL Function
-    -- | <http://www.sqlite.org/c3ref/result_blob.html>
+    -- | <https://www.sqlite.org/c3ref/result_blob.html>
     c_sqlite3_result_null,
     c_sqlite3_result_blob,
     c_sqlite3_result_zeroblob,
@@ -98,6 +99,7 @@
 
     -- * Miscellaneous
     c_sqlite3_free,
+    c_sqlite3_free_p,
 
     -- * Extensions
     c_sqlite3_enable_load_extension,
@@ -130,54 +132,53 @@
 import Foreign
 import Foreign.C
 
-
--- | <http://www.sqlite.org/c3ref/open.html>
+-- | <https://www.sqlite.org/c3ref/open.html>
 --
 -- This sets the @'Ptr CDatabase'@ even on failure.
 foreign import ccall "sqlite3_open"
     c_sqlite3_open :: CString -> Ptr (Ptr CDatabase) -> IO CError
 
--- | <http://www.sqlite.org/c3ref/close.html>
+-- | <https://www.sqlite.org/c3ref/close.html>
 foreign import ccall "sqlite3_close"
     c_sqlite3_close :: Ptr CDatabase -> IO CError
 
--- | <http://www.sqlite.org/c3ref/errcode.html>
-foreign import ccall "sqlite3_errcode"
+-- | <https://www.sqlite.org/c3ref/errcode.html>
+foreign import ccall unsafe "sqlite3_errcode"
     c_sqlite3_errcode :: Ptr CDatabase -> IO CError
 
--- | <http://www.sqlite.org/c3ref/errcode.html>
-foreign import ccall "sqlite3_errmsg"
+-- | <https://www.sqlite.org/c3ref/errcode.html>
+foreign import ccall unsafe "sqlite3_errmsg"
     c_sqlite3_errmsg :: Ptr CDatabase -> IO CString
 
--- | <http://www.sqlite.org/c3ref/interrupt.html>
+-- | <https://www.sqlite.org/c3ref/interrupt.html>
 foreign import ccall "sqlite3_interrupt"
     c_sqlite3_interrupt :: Ptr CDatabase -> IO ()
 
--- | <http://www.sqlite.org/c3ref/profile.html>
+-- | <https://www.sqlite.org/c3ref/profile.html>
 foreign import ccall "sqlite3_trace"
     c_sqlite3_trace
         :: Ptr CDatabase
-        -> FunPtr (CTraceCallback a) -- ^ Optional callback function called for each row
-        -> Ptr a                     -- ^ Context passed to the callback
-        -> IO (Ptr ())               -- ^ Returns context pointer from previously
-                                     --   registered trace
+        -> FunPtr (CTraceCallback a) -- ^ Optional callback function called for each row.
+        -> Ptr a                     -- ^ Context passed to the callback.
+        -> IO (Ptr ())               -- ^ Returns context pointer from previously.
+                                     --   registered trace.
 
--- | <http://www.sqlite.org/c3ref/get_autocommit.html>
+-- | <https://www.sqlite.org/c3ref/get_autocommit.html>
 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
-
+    c_sqlite3_enable_shared_cache :: Bool -> IO CError
 
+-- | <https://www.sqlite.org/c3ref/exec.html>
 foreign import ccall "sqlite3_exec"
     c_sqlite3_exec
         :: Ptr CDatabase
-        -> CString                  -- ^ SQL statement, UTF-8 encoded
-        -> FunPtr (CExecCallback a) -- ^ Optional callback function called for each row
-        -> Ptr a                    -- ^ Context passed to the callback
-        -> Ptr CString              -- ^ OUT: Error message string
+        -> CString                  -- ^ SQL statement, UTF-8 encoded.
+        -> FunPtr (CExecCallback a) -- ^ Optional callback function called for each row.
+        -> Ptr a                    -- ^ Context passed to the callback.
+        -> Ptr CString              -- ^ OUT: Error message string.
         -> IO CError
 
 type CExecCallback a
@@ -195,7 +196,7 @@
 type CTraceCallback a
      = Ptr a
     -> CString      -- ^ UTF-8 rendering of the SQL statement text as
-                    -- the statement first begins executing
+                    --   the statement first begins executing.
     -> IO ()
 
 -- | A couple important things to know about callbacks from Haskell code:
@@ -211,56 +212,59 @@
 foreign import ccall "wrapper"
     mkCTraceCallback :: CTraceCallback a -> IO (FunPtr (CTraceCallback a))
 
-
--- | <http://www.sqlite.org/c3ref/prepare.html>
+-- | <https://www.sqlite.org/c3ref/prepare.html>
 --
 -- If the query contains no SQL statements, this returns @SQLITE_OK@ and sets
 -- the @'Ptr' 'CStatement'@ to null.
 foreign import ccall "sqlite3_prepare_v2"
     c_sqlite3_prepare_v2
         :: Ptr CDatabase
-        -> CString              -- ^ SQL statement, UTF-8 encoded
+        -> CString              -- ^ SQL statement, UTF-8 encoded.
         -> CNumBytes            -- ^ Maximum length of the SQL statement,
                                 --   in bytes.  If this is negative, then the
                                 --   SQL statement is treated as a
                                 --   NUL-terminated string.
         -> Ptr (Ptr CStatement) -- ^ OUT: Statement handle.  This must not be null.
-        -> Ptr CString          -- ^ OUT: Pointer to unused portion of zSql
+        -> Ptr CString          -- ^ OUT: Pointer to unused portion of zSql.
         -> IO CError
 
--- | <http://www.sqlite.org/c3ref/db_handle.html>
+-- | <https://www.sqlite.org/c3ref/db_handle.html>
 foreign import ccall unsafe "sqlite3_db_handle"
     c_sqlite3_db_handle :: Ptr CStatement -> IO (Ptr CDatabase)
 
--- | <http://www.sqlite.org/c3ref/step.html>
+-- | <https://www.sqlite.org/c3ref/step.html>
 foreign import ccall "sqlite3_step"
     c_sqlite3_step :: Ptr CStatement -> IO CError
 
--- | <http://www.sqlite.org/c3ref/reset.html>
+-- | <https://www.sqlite.org/c3ref/step.html>
+foreign import ccall unsafe "sqlite3_step"
+    c_sqlite3_step_unsafe :: Ptr CStatement -> IO CError
+
+-- | <https://www.sqlite.org/c3ref/reset.html>
 --
 -- /Warning:/ If the most recent 'c_sqlite3_step' call failed,
 -- this will return the corresponding error code.
-foreign import ccall "sqlite3_reset"
+foreign import ccall unsafe "sqlite3_reset"
     c_sqlite3_reset :: Ptr CStatement -> IO CError
 
--- | <http://www.sqlite.org/c3ref/finalize.html>
+-- | <https://www.sqlite.org/c3ref/finalize.html>
 --
 -- /Warning:/ If the most recent 'c_sqlite3_step' call failed,
 -- this will return the corresponding error code.
 foreign import ccall "sqlite3_finalize"
     c_sqlite3_finalize :: Ptr CStatement -> IO CError
 
--- | <http://www.sqlite.org/c3ref/clear_bindings.html>
+-- | <https://www.sqlite.org/c3ref/clear_bindings.html>
 --
 -- A look at the source reveals that this function always returns @SQLITE_OK@.
 foreign import ccall unsafe "sqlite3_clear_bindings"
     c_sqlite3_clear_bindings :: Ptr CStatement -> IO CError
 
--- | <http://www.sqlite.org/c3ref/sql.html>
+-- | <https://www.sqlite.org/c3ref/sql.html>
 foreign import ccall unsafe "sqlite3_sql"
     c_sqlite3_sql :: Ptr CStatement -> IO CString
 
--- | <http://www.sqlite.org/c3ref/bind_parameter_count.html>
+-- | <https://www.sqlite.org/c3ref/bind_parameter_count.html>
 --
 -- This returns the index of the largest (rightmost) parameter, which is not
 -- necessarily the number of parameters.  If numbered parameters like @?5@
@@ -268,23 +272,23 @@
 foreign import ccall unsafe "sqlite3_bind_parameter_count"
     c_sqlite3_bind_parameter_count :: Ptr CStatement -> IO CParamIndex
 
--- | <http://www.sqlite.org/c3ref/bind_parameter_name.html>
+-- | <https://www.sqlite.org/c3ref/bind_parameter_name.html>
 foreign import ccall unsafe "sqlite3_bind_parameter_name"
     c_sqlite3_bind_parameter_name :: Ptr CStatement -> CParamIndex -> IO CString
 
--- | <http://www.sqlite.org/c3ref/bind_parameter_index.html>
+-- | <https://www.sqlite.org/c3ref/bind_parameter_index.html>
 foreign import ccall unsafe "sqlite3_bind_parameter_index"
     c_sqlite3_bind_parameter_index :: Ptr CStatement -> CString -> IO CParamIndex
 
--- | <http://www.sqlite.org/c3ref/column_count.html>
+-- | <https://www.sqlite.org/c3ref/column_count.html>
 foreign import ccall unsafe "sqlite3_column_count"
     c_sqlite3_column_count :: Ptr CStatement -> IO CColumnCount
 
--- | <http://www.sqlite.org/c3ref/column_name.html>
+-- | <https://www.sqlite.org/c3ref/column_name.html>
 foreign import ccall unsafe "sqlite3_column_name"
     c_sqlite3_column_name :: Ptr CStatement -> CColumnIndex -> IO CString
 
-
+-- | <https://www.sqlite.org/c3ref/bind_blob.html>
 foreign import ccall unsafe "sqlite3_bind_blob"
     c_sqlite3_bind_blob
         :: Ptr CStatement
@@ -297,10 +301,12 @@
         -> Ptr CDestructor
         -> IO CError
 
+-- | <https://www.sqlite.org/c3ref/bind_blob.html>
 foreign import ccall unsafe "sqlite3_bind_zeroblob"
     c_sqlite3_bind_zeroblob
         :: Ptr CStatement -> CParamIndex -> CInt -> IO CError
 
+-- | <https://www.sqlite.org/c3ref/bind_blob.html>
 foreign import ccall unsafe "sqlite3_bind_text"
     c_sqlite3_bind_text
         :: Ptr CStatement
@@ -312,57 +318,64 @@
         -> Ptr CDestructor
         -> IO CError
 
+-- | <https://www.sqlite.org/c3ref/bind_blob.html>
 foreign import ccall unsafe "sqlite3_bind_double"
     c_sqlite3_bind_double   :: Ptr CStatement -> CParamIndex -> Double -> IO CError
 
+-- | <https://www.sqlite.org/c3ref/bind_blob.html>
 foreign import ccall unsafe "sqlite3_bind_int64"
     c_sqlite3_bind_int64    :: Ptr CStatement -> CParamIndex -> Int64 -> IO CError
 
+-- | <https://www.sqlite.org/c3ref/bind_blob.html>
 foreign import ccall unsafe "sqlite3_bind_null"
     c_sqlite3_bind_null     :: Ptr CStatement -> CParamIndex -> IO CError
 
-
+-- | <https://www.sqlite.org/c3ref/column_blob.html>
 foreign import ccall unsafe "sqlite3_column_type"
     c_sqlite3_column_type   :: Ptr CStatement -> CColumnIndex -> IO CColumnType
 
+-- | <https://www.sqlite.org/c3ref/column_blob.html>
 foreign import ccall unsafe "sqlite3_column_bytes"
     c_sqlite3_column_bytes  :: Ptr CStatement -> CColumnIndex -> IO CNumBytes
 
+-- | <https://www.sqlite.org/c3ref/column_blob.html>
 foreign import ccall unsafe "sqlite3_column_blob"
     c_sqlite3_column_blob   :: Ptr CStatement -> CColumnIndex -> IO (Ptr a)
 
+-- | <https://www.sqlite.org/c3ref/column_blob.html>
 foreign import ccall unsafe "sqlite3_column_text"
     c_sqlite3_column_text   :: Ptr CStatement -> CColumnIndex -> IO CString
 
+-- | <https://www.sqlite.org/c3ref/column_blob.html>
 foreign import ccall unsafe "sqlite3_column_int64"
     c_sqlite3_column_int64  :: Ptr CStatement -> CColumnIndex -> IO Int64
 
+-- | <https://www.sqlite.org/c3ref/column_blob.html>
 foreign import ccall unsafe "sqlite3_column_double"
     c_sqlite3_column_double :: Ptr CStatement -> CColumnIndex -> IO Double
 
-
--- | <http://www.sqlite.org/c3ref/last_insert_rowid.html>
+-- | <https://www.sqlite.org/c3ref/last_insert_rowid.html>
 foreign import ccall unsafe "sqlite3_last_insert_rowid"
     c_sqlite3_last_insert_rowid :: Ptr CDatabase -> IO Int64
 
--- | <http://www.sqlite.org/c3ref/changes.html>
+-- | <https://www.sqlite.org/c3ref/changes.html>
 foreign import ccall unsafe "sqlite3_changes"
     c_sqlite3_changes :: Ptr CDatabase -> IO CInt
 
--- | <http://www.sqlite.org/c3ref/total_changes.html>
+-- | <https://www.sqlite.org/c3ref/total_changes.html>
 foreign import ccall unsafe "sqlite3_total_changes"
     c_sqlite3_total_changes :: Ptr CDatabase -> IO CInt
 
 -- do not use unsafe import here, it might call back to haskell
 -- via the CFuncDestroy argument
--- | <http://sqlite.org/c3ref/create_function.html>
+-- | <https://sqlite.org/c3ref/create_function.html>
 foreign import ccall "sqlite3_create_function_v2"
     c_sqlite3_create_function_v2
         :: Ptr CDatabase
-        -> CString         -- ^ Name of the function
-        -> CArgCount       -- ^ Number of arguments
-        -> CInt            -- ^ Preferred text encoding (also used to pass flags)
-        -> Ptr a           -- ^ User data
+        -> CString         -- ^ Name of the function.
+        -> CArgCount       -- ^ Number of arguments.
+        -> CInt            -- ^ Preferred text encoding (also used to pass flags).
+        -> Ptr a           -- ^ User data.
         -> FunPtr CFunc
         -> FunPtr CFunc
         -> FunPtr CFuncFinal
@@ -384,70 +397,81 @@
 foreign import ccall "wrapper"
     mkCFuncDestroy :: CFuncDestroy a -> IO (FunPtr (CFuncDestroy a))
 
--- | <http://www.sqlite.org/c3ref/user_data.html>
+-- | <https://www.sqlite.org/c3ref/user_data.html>
 foreign import ccall unsafe "sqlite3_user_data"
     c_sqlite3_user_data :: Ptr CContext -> IO (Ptr a)
 
--- | <http://www.sqlite.org/c3ref/context_db_handle.html>
+-- | <https://www.sqlite.org/c3ref/context_db_handle.html>
 foreign import ccall unsafe "sqlite3_context_db_handle"
     c_sqlite3_context_db_handle :: Ptr CContext -> IO (Ptr CDatabase)
 
--- | <http://www.sqlite.org/c3ref/aggregate_context.html>
+-- | <https://www.sqlite.org/c3ref/aggregate_context.html>
 foreign import ccall unsafe "sqlite3_aggregate_context"
     c_sqlite3_aggregate_context :: Ptr CContext -> CNumBytes -> IO (Ptr a)
 
-
+-- | <https://www.sqlite.org/c3ref/value_blob.html>
 foreign import ccall unsafe "sqlite3_value_type"
     c_sqlite3_value_type   :: Ptr CValue -> IO CColumnType
 
+-- | <https://www.sqlite.org/c3ref/value_blob.html>
 foreign import ccall unsafe "sqlite3_value_bytes"
     c_sqlite3_value_bytes  :: Ptr CValue -> IO CNumBytes
 
+-- | <https://www.sqlite.org/c3ref/value_blob.html>
 foreign import ccall unsafe "sqlite3_value_blob"
     c_sqlite3_value_blob   :: Ptr CValue -> IO (Ptr a)
 
+-- | <https://www.sqlite.org/c3ref/value_blob.html>
 foreign import ccall unsafe "sqlite3_value_text"
     c_sqlite3_value_text   :: Ptr CValue -> IO CString
 
+-- | <https://www.sqlite.org/c3ref/value_blob.html>
 foreign import ccall unsafe "sqlite3_value_int64"
     c_sqlite3_value_int64  :: Ptr CValue -> IO Int64
 
+-- | <https://www.sqlite.org/c3ref/value_blob.html>
 foreign import ccall unsafe "sqlite3_value_double"
     c_sqlite3_value_double :: Ptr CValue -> IO Double
 
-
+-- | <https://www.sqlite.org/c3ref/result_blob.html>
 foreign import ccall unsafe "sqlite3_result_null"
     c_sqlite3_result_null     :: Ptr CContext -> IO ()
 
+-- | <https://www.sqlite.org/c3ref/result_blob.html>
 foreign import ccall unsafe "sqlite3_result_blob"
     c_sqlite3_result_blob     :: Ptr CContext -> Ptr a -> CNumBytes -> Ptr CDestructor -> IO ()
 
+-- | <https://www.sqlite.org/c3ref/result_blob.html>
 foreign import ccall unsafe "sqlite3_result_zeroblob"
     c_sqlite3_result_zeroblob :: Ptr CContext -> CNumBytes -> IO ()
 
+-- | <https://www.sqlite.org/c3ref/result_blob.html>
 foreign import ccall unsafe "sqlite3_result_text"
     c_sqlite3_result_text     :: Ptr CContext -> CString -> CNumBytes -> Ptr CDestructor -> IO ()
 
+-- | <https://www.sqlite.org/c3ref/result_blob.html>
 foreign import ccall unsafe "sqlite3_result_int64"
     c_sqlite3_result_int64    :: Ptr CContext -> Int64 -> IO ()
 
+-- | <https://www.sqlite.org/c3ref/result_blob.html>
 foreign import ccall unsafe "sqlite3_result_double"
     c_sqlite3_result_double   :: Ptr CContext -> Double -> IO ()
 
+-- | <https://www.sqlite.org/c3ref/result_blob.html>
 foreign import ccall unsafe "sqlite3_result_value"
     c_sqlite3_result_value    :: Ptr CContext -> Ptr CValue -> IO ()
 
+-- | <https://www.sqlite.org/c3ref/result_blob.html>
 foreign import ccall unsafe "sqlite3_result_error"
     c_sqlite3_result_error    :: Ptr CContext -> CString -> CNumBytes -> IO ()
 
-
--- | <http://www.sqlite.org/c3ref/create_collation.html>
+-- | <https://www.sqlite.org/c3ref/create_collation.html>
 foreign import ccall "sqlite3_create_collation_v2"
     c_sqlite3_create_collation_v2
         :: Ptr CDatabase
-        -> CString         -- ^ Name of the collation
-        -> CInt            -- ^ Text encoding
-        -> Ptr a           -- ^ User data
+        -> CString         -- ^ Name of the collation.
+        -> CInt            -- ^ Text encoding.
+        -> Ptr a           -- ^ User data.
         -> FunPtr (CCompare a)
         -> FunPtr (CFuncDestroy a)
         -> IO CError
@@ -457,17 +481,18 @@
 foreign import ccall "wrapper"
     mkCCompare :: CCompare a -> IO (FunPtr (CCompare a))
 
-
--- | <http://sqlite.org/c3ref/free.html>
+-- | <https://sqlite.org/c3ref/free.html>
 foreign import ccall "sqlite3_free"
     c_sqlite3_free :: Ptr a -> IO ()
 
+-- | <https://sqlite.org/c3ref/free.html>
+foreign import ccall "&sqlite3_free"
+    c_sqlite3_free_p :: FunPtr (Ptr a -> IO ())
 
--- | <http://sqlite.org/c3ref/enable_load_extension.html>
+-- | <https://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 ())
@@ -477,25 +502,24 @@
 foreign import ccall "wrapper"
     mkCWalHook :: CWalHook -> IO (FunPtr CWalHook)
 
-
 -- | <https://www.sqlite.org/c3ref/blob_open.html>
-foreign import ccall "sqlite3_blob_open"
+foreign import ccall unsafe "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
+        -> 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"
+foreign import ccall unsafe "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"
+foreign import ccall unsafe "sqlite3_blob_reopen"
     c_sqlite3_blob_reopen :: Ptr CBlob -> Int64 -> IO CError
 
 -- | <https://www.sqlite.org/c3ref/blob_bytes.html>
@@ -503,30 +527,34 @@
     c_sqlite3_blob_bytes :: Ptr CBlob -> IO CInt
 
 -- | <https://www.sqlite.org/c3ref/blob_read.html>
-foreign import ccall "sqlite3_blob_read"
+foreign import ccall unsafe "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"
+foreign import ccall unsafe "sqlite3_blob_write"
     c_sqlite3_blob_write :: Ptr CBlob -> Ptr a -> CInt -> CInt -> IO CError
 
-
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupinit>
 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
+        :: Ptr CDatabase  -- ^ Destination database handle.
+        -> CString        -- ^ Destination database name.
+        -> Ptr CDatabase  -- ^ Source database handle.
+        -> CString        -- ^ Source database name.
         -> IO (Ptr CBackup)
 
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish>
 foreign import ccall "sqlite3_backup_finish"
     c_sqlite3_backup_finish :: Ptr CBackup -> IO CError
 
-foreign import ccall "sqlite3_backup_step"
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupstep>
+foreign import ccall unsafe "sqlite3_backup_step"
     c_sqlite3_backup_step :: Ptr CBackup -> CInt -> IO CError
 
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupremaining>
 foreign import ccall unsafe "sqlite3_backup_remaining"
     c_sqlite3_backup_remaining :: Ptr CBackup -> IO CInt
 
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backuppagecount>
 foreign import ccall unsafe "sqlite3_backup_pagecount"
     c_sqlite3_backup_pagecount :: Ptr CBackup -> IO CInt
diff --git a/Database/SQLite3/Bindings/Types.hsc b/Database/SQLite3/Bindings/Types.hsc
--- a/Database/SQLite3/Bindings/Types.hsc
+++ b/Database/SQLite3/Bindings/Types.hsc
@@ -4,7 +4,7 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 module Database.SQLite3.Bindings.Types (
     -- * Objects
-    -- | <http://www.sqlite.org/c3ref/objlist.html>
+    -- | <https://www.sqlite.org/c3ref/objlist.html>
     CDatabase,
     CStatement,
     CValue,
@@ -39,6 +39,7 @@
     -- * Miscellaneous
     CNumBytes(..),
     CDestructor,
+    c_SQLITE_STATIC,
     c_SQLITE_TRANSIENT,
     c_SQLITE_UTF8,
 
@@ -61,8 +62,9 @@
 import Foreign.C.Types
 import Foreign.Ptr
 
--- Result code documentation copied from <http://www.sqlite.org/c3ref/c_abort.html>
+-- Result code documentation copied from <https://www.sqlite.org/c3ref/c_abort.html>
 
+-- | <https://www.sqlite.org/c3ref/c_abort.html>
 data Error = ErrorOK                     -- ^ Successful result
            | ErrorError                  -- ^ SQL error or missing database
            | ErrorInternal               -- ^ Internal logic error in SQLite
@@ -90,10 +92,13 @@
            | ErrorFormat                 -- ^ Auxiliary database format error
            | ErrorRange                  -- ^ 2nd parameter to sqlite3_bind out of range
            | ErrorNotADatabase           -- ^ File opened that is not a database file
+           | ErrorNotice                 -- ^ Notifications from sqlite3_log()
+           | ErrorWarning                -- ^ Warnings from sqlite3_log()
            | ErrorRow                    -- ^ @sqlite3_step()@ has another row ready
            | ErrorDone                   -- ^ @sqlite3_step()@ has finished executing
              deriving (Eq, Show)
 
+-- | <https://www.sqlite.org/c3ref/c_blob.html>
 data ColumnType = IntegerColumn
                 | FloatColumn
                 | TextColumn
@@ -101,22 +106,22 @@
                 | NullColumn
                   deriving (Eq, Show)
 
--- | <http://www.sqlite.org/c3ref/sqlite3.html>
+-- | <https://www.sqlite.org/c3ref/sqlite3.html>
 --
 -- @CDatabase@ = @sqlite3@
 data CDatabase
 
--- | <http://www.sqlite.org/c3ref/stmt.html>
+-- | <https://www.sqlite.org/c3ref/stmt.html>
 --
 -- @CStatement@ = @sqlite3_stmt@
 data CStatement
 
--- | <http://www.sqlite.org/c3ref/value.html>
+-- | <https://www.sqlite.org/c3ref/value.html>
 --
 -- @CValue@ = @sqlite3_value@
 data CValue
 
--- | <http://www.sqlite.org/c3ref/context.html>
+-- | <https://www.sqlite.org/c3ref/context.html>
 --
 -- @CContext@ = @sqlite3_context@
 data CContext
@@ -146,7 +151,7 @@
 -- When you bind a parameter with 'Database.SQLite3.bindSQLData', it assigns a
 -- new value to one of these indices.
 --
--- See <http://www.sqlite.org/lang_expr.html#varparam> for the syntax of
+-- See <https://www.sqlite.org/lang_expr.html#varparam> for the syntax of
 -- parameter placeholders, and how parameter indices are assigned.
 newtype ParamIndex = ParamIndex Int
     deriving (Eq, Ord, Enum, Num, Real, Integral)
@@ -195,11 +200,15 @@
 newtype CNumBytes = CNumBytes CInt
     deriving (Eq, Ord, Show, Enum, Num, Real, Integral)
 
--- | <http://www.sqlite.org/c3ref/c_static.html>
+-- | <https://www.sqlite.org/c3ref/c_static.html>
 --
 -- @Ptr CDestructor@ = @sqlite3_destructor_type@
 data CDestructor
 
+-- | Tells SQLite3 that the content pointer is constant and will never change
+c_SQLITE_STATIC :: Ptr CDestructor
+c_SQLITE_STATIC = intPtrToPtr 0
+
 -- | Tells SQLite3 to make its own private copy of the data
 c_SQLITE_TRANSIENT :: Ptr CDestructor
 c_SQLITE_TRANSIENT = intPtrToPtr (-1)
@@ -207,7 +216,6 @@
 c_SQLITE_UTF8 :: CInt
 c_SQLITE_UTF8 = #{const SQLITE_UTF8}
 
-
 -- | Number of arguments of a user defined SQL function.
 newtype ArgCount = ArgCount Int
     deriving (Eq, Ord, Enum, Num, Real, Integral)
@@ -238,8 +246,7 @@
 c_SQLITE_DETERMINISTIC :: CInt
 c_SQLITE_DETERMINISTIC = #{const SQLITE_DETERMINISTIC}
 
-
--- | <http://www.sqlite.org/c3ref/c_abort.html>
+-- | <https://www.sqlite.org/c3ref/c_abort.html>
 newtype CError = CError CInt
     deriving (Eq, Show)
 
@@ -251,7 +258,7 @@
 -- exception you can handle.
 --
 -- Therefore, do not use direct-sqlite with a different version of SQLite than
--- the one bundled (currently, 3.7.13).  If you do, ensure that 'decodeError'
+-- the one bundled (currently, 3.24.0).  If you do, ensure that 'decodeError'
 -- and 'decodeColumnType' are still exhaustive.
 decodeError :: CError -> Error
 decodeError (CError n) = case n of
@@ -282,6 +289,8 @@
     #{const SQLITE_FORMAT}     -> ErrorFormat
     #{const SQLITE_RANGE}      -> ErrorRange
     #{const SQLITE_NOTADB}     -> ErrorNotADatabase
+    #{const SQLITE_NOTICE}     -> ErrorNotice
+    #{const SQLITE_WARNING}    -> ErrorWarning
     #{const SQLITE_ROW}        -> ErrorRow
     #{const SQLITE_DONE}       -> ErrorDone
     _                          -> error $ "decodeError " ++ show n
@@ -315,11 +324,12 @@
     ErrorFormat             -> #const SQLITE_FORMAT
     ErrorRange              -> #const SQLITE_RANGE
     ErrorNotADatabase       -> #const SQLITE_NOTADB
+    ErrorNotice             -> #const SQLITE_NOTICE
+    ErrorWarning            -> #const SQLITE_WARNING
     ErrorRow                -> #const SQLITE_ROW
     ErrorDone               -> #const SQLITE_DONE
 
-
--- | <http://www.sqlite.org/c3ref/c_blob.html>
+-- | <https://www.sqlite.org/c3ref/c_blob.html>
 newtype CColumnType = CColumnType CInt
     deriving (Eq, Show)
 
diff --git a/Database/SQLite3/Direct.hs b/Database/SQLite3/Direct.hs
--- a/Database/SQLite3/Direct.hs
+++ b/Database/SQLite3/Direct.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 -- |
 -- This API is a slightly lower-level version of "Database.SQLite3".  Namely:
@@ -19,7 +19,7 @@
     setSharedCacheEnabled,
 
     -- * Simple query execution
-    -- | <http://sqlite.org/c3ref/exec.html>
+    -- | <https://sqlite.org/c3ref/exec.html>
     exec,
     execWithCallback,
     ExecCallback,
@@ -28,6 +28,7 @@
     prepare,
     getStatementDatabase,
     step,
+    stepNoCB,
     reset,
     finalize,
     clearBindings,
@@ -41,7 +42,7 @@
     columnName,
 
     -- * Binding values to a prepared statement
-    -- | <http://www.sqlite.org/c3ref/bind_blob.html>
+    -- | <https://www.sqlite.org/c3ref/bind_blob.html>
     bindInt64,
     bindDouble,
     bindText,
@@ -50,7 +51,7 @@
     bindNull,
 
     -- * Reading the result row
-    -- | <http://www.sqlite.org/c3ref/column_blob.html>
+    -- | <https://www.sqlite.org/c3ref/column_blob.html>
     columnType,
     columnInt64,
     columnDouble,
@@ -137,16 +138,14 @@
 
 import qualified Data.ByteString            as BS
 import qualified Data.ByteString.Unsafe     as BSU
-import qualified Data.List.NonEmpty         as NEL
-import Data.Semigroup       (Semigroup ((<>), sconcat))
+import qualified Data.ByteString.Internal   as BSI
+import Data.Semigroup       (Semigroup)
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
-import Control.Applicative  ((<$>))
 import Control.Exception as E
 import Control.Monad        (join, unless)
 import Data.ByteString      (ByteString)
 import Data.IORef
-import Data.Monoid          (Monoid (mempty, mappend, mconcat))
 import Data.String          (IsString(..))
 import Data.Text.Encoding.Error (lenientDecode)
 import Foreign
@@ -171,7 +170,7 @@
 
 -- | A 'ByteString' containing UTF8-encoded text with no NUL characters.
 newtype Utf8 = Utf8 ByteString
-    deriving (Eq, Ord)
+    deriving (Eq, Ord, Semigroup, Monoid)
 
 instance Show Utf8 where
     show (Utf8 s) = (show . T.decodeUtf8With lenientDecode) s
@@ -180,15 +179,6 @@
 instance IsString Utf8 where
     fromString = Utf8 . T.encodeUtf8 . T.pack
 
-instance Semigroup Utf8 where
-    Utf8 a <> Utf8 b = Utf8 (BS.append a b)
-    sconcat = Utf8 . BS.concat . NEL.toList . fmap (\(Utf8 s) -> s)
-
-instance Monoid Utf8 where
-    mempty = Utf8 BS.empty
-    mappend = (<>)
-    mconcat = Utf8 . BS.concat . map (\(Utf8 s) -> s)
-
 packUtf8 :: a -> (Utf8 -> a) -> CString -> IO a
 packUtf8 n f cstr | cstr == nullPtr = return n
                   | otherwise       = f . Utf8 <$> BS.packCString cstr
@@ -213,29 +203,27 @@
 wrapNullablePtr f ptr | ptr == nullPtr = Nothing
                       | otherwise      = Just (f ptr)
 
-type Result a = Either Error a
-
--- Convert a 'CError' to a 'Result', in the common case where
+-- Convert a 'CError' to a 'Either Error', in the common case where
 -- SQLITE_OK signals success and anything else signals an error.
 --
 -- Note that SQLITE_OK == 0.
-toResult :: a -> CError -> Result a
+toResult :: a -> CError -> Either Error a
 toResult a (CError 0) = Right a
 toResult _ code       = Left $ decodeError code
 
 -- Only perform the action if the 'CError' is SQLITE_OK.
-toResultM :: Monad m => m a -> CError -> m (Result a)
-toResultM m (CError 0) = m >>= return . Right
+toResultM :: Monad m => m a -> CError -> m (Either Error a)
+toResultM m (CError 0) = Right <$> m
 toResultM _ code       = return $ Left $ decodeError code
 
-toStepResult :: CError -> Result StepResult
+toStepResult :: CError -> Either Error StepResult
 toStepResult code =
     case decodeError code of
         ErrorRow  -> Right Row
         ErrorDone -> Right Done
         err       -> Left err
 
-toBackupStepResult :: CError -> Result BackupStepResult
+toBackupStepResult :: CError -> Either Error BackupStepResult
 toBackupStepResult code =
     case decodeError code of
         ErrorOK   -> Right BackupOK
@@ -262,7 +250,7 @@
 
 ------------------------------------------------------------------------
 
--- | <http://www.sqlite.org/c3ref/open.html>
+-- | <https://www.sqlite.org/c3ref/open.html>
 open :: Utf8 -> IO (Either (Error, Utf8) Database)
 open (Utf8 path) =
     BS.useAsCString path $ \path' ->
@@ -281,12 +269,12 @@
                     then fail "sqlite3_open unexpectedly returned NULL"
                     else return $ Right db
 
--- | <http://www.sqlite.org/c3ref/close.html>
+-- | <https://www.sqlite.org/c3ref/close.html>
 close :: Database -> IO (Either Error ())
 close (Database db) =
     toResult () <$> c_sqlite3_close db
 
--- | <http://www.sqlite.org/c3ref/interrupt.html>
+-- | <https://www.sqlite.org/c3ref/interrupt.html>
 --
 -- Cause any pending operation on the 'Database' handle to stop at its earliest
 -- opportunity.  This simply sets a flag and returns immediately.  It does not
@@ -299,29 +287,40 @@
 interrupt (Database db) =
     c_sqlite3_interrupt db
 
--- | <http://www.sqlite.org/c3ref/errcode.html>
+-- | <https://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>
+-- | <https://www.sqlite.org/c3ref/errcode.html>
 errmsg :: Database -> IO Utf8
 errmsg (Database db) =
-    c_sqlite3_errmsg db >>= packUtf8 (Utf8 BS.empty) id
+    c_sqlite3_errmsg db >>= packUtf8 mempty id
 
-exec :: Database -> Utf8 -> IO (Either (Error, Utf8) ())
-exec (Database db) (Utf8 sql) =
-    BS.useAsCString sql $ \sql' ->
-    alloca $ \msgPtrOut -> do
-        rc <- c_sqlite3_exec db sql' nullFunPtr nullPtr msgPtrOut
+withErrorMessagePtr :: (Ptr CString -> IO CError) -> IO (Either (Error, Utf8) ())
+withErrorMessagePtr action =
+    alloca $ \msgPtrOut -> mask $ \restore -> do
+        poke msgPtrOut nullPtr
+        rc <- restore (action msgPtrOut)
+            `onException` (peek msgPtrOut >>= c_sqlite3_free)
         case toResult () rc of
             Left err -> do
                 msgPtr <- peek msgPtrOut
-                msg <- packUtf8 (Utf8 BS.empty) id msgPtr
-                c_sqlite3_free msgPtr
-                return $ Left (err, msg)
-            Right () -> return $ Right ()
+                if msgPtr == nullPtr
+                    then return (Left (err, mempty))
+                    else do
+                        len <- BSI.c_strlen msgPtr
+                        fp <- newForeignPtr c_sqlite3_free_p msgPtr
+                        let bs = BSI.fromForeignPtr (castForeignPtr fp) 0 (fromIntegral len)
+                        return (Left (err, Utf8 bs))
+            Right () -> return (Right ())
 
+-- | <https://www.sqlite.org/c3ref/exec.html>
+exec :: Database -> Utf8 -> IO (Either (Error, Utf8) ())
+exec (Database db) (Utf8 sql) =
+    BS.useAsCString sql $ \sql' ->
+        withErrorMessagePtr (c_sqlite3_exec db sql' nullFunPtr nullPtr)
+
 -- | Like 'exec', but invoke the callback for each result row.
 --
 -- If the callback throws an exception, it will be rethrown by
@@ -360,23 +359,15 @@
             cb' values
 
     BS.useAsCString sql $ \sql' ->
-      alloca $ \msgPtrOut ->
-      bracket (mkCExecCallback cExecCallback) freeHaskellFunPtr $
-      \pExecCallback -> do
-        let returnError err = do
-                msgPtr <- peek msgPtrOut
-                msg <- packUtf8 (Utf8 BS.empty) id msgPtr
-                c_sqlite3_free msgPtr
-                return $ Left (err, msg)
-        rc <- c_sqlite3_exec db sql' pExecCallback nullPtr msgPtrOut
-        case toResult () rc of
-            Left ErrorAbort -> do
-                m <- readIORef abortReason
-                case m of
-                    Nothing -> returnError ErrorAbort
-                    Just ex -> throwIO ex
-            Left err -> returnError err
-            Right () -> return $ Right ()
+        bracket (mkCExecCallback cExecCallback) freeHaskellFunPtr $ \pExecCallback -> do
+            e <- withErrorMessagePtr (c_sqlite3_exec db sql' pExecCallback nullPtr)
+            case e of
+                Left r@(ErrorAbort, _) -> do
+                    m <- readIORef abortReason
+                    case m of
+                        Nothing -> return (Left r)
+                        Just ex -> throwIO ex
+                r               -> return r
 
 type ExecCallback
      = ColumnCount    -- ^ Number of columns, which is the number of items in
@@ -387,7 +378,7 @@
     -> [Maybe Utf8]   -- ^ List of column values, as returned by 'columnText'.
     -> IO ()
 
--- | <http://www.sqlite.org/c3ref/profile.html>
+-- | <https://www.sqlite.org/c3ref/profile.html>
 --
 -- Enable/disable tracing of SQL execution.  Tracing can be disabled
 -- by setting 'Nothing' as the logger callback.
@@ -405,12 +396,12 @@
             -- though, since 'setTrace' is mainly for debugging, and is
             -- typically only called once per application invocation.
             cb <- mkCTraceCallback $ \_ctx cStr -> do
-                msg <- packUtf8 (Utf8 BS.empty) id cStr
+                msg <- packUtf8 mempty id cStr
                 output msg
             _ <- c_sqlite3_trace db cb nullPtr
             return ()
 
--- | <http://www.sqlite.org/c3ref/get_autocommit.html>
+-- | <https://www.sqlite.org/c3ref/get_autocommit.html>
 --
 -- Return 'True' if the connection is in autocommit mode, or 'False' if a
 -- transaction started with @BEGIN@ is still active.
@@ -428,17 +419,14 @@
 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)
-
+    toResult () <$> c_sqlite3_enable_shared_cache val
 
--- | <http://www.sqlite.org/c3ref/prepare.html>
+-- | <https://www.sqlite.org/c3ref/prepare.html>
 --
 -- If the query contains no SQL statements, this returns
 -- @'Right' 'Nothing'@.
@@ -449,7 +437,7 @@
             c_sqlite3_prepare_v2 db sql' (-1) statement nullPtr >>=
                 toResultM (wrapNullablePtr Statement <$> peek statement)
 
--- | <http://www.sqlite.org/c3ref/db_handle.html>
+-- | <https://www.sqlite.org/c3ref/db_handle.html>
 getStatementDatabase :: Statement -> IO Database
 getStatementDatabase (Statement stmt) = do
     db <- c_sqlite3_db_handle stmt
@@ -457,13 +445,21 @@
         then fail $ "sqlite3_db_handle(" ++ show stmt ++ ") returned NULL"
         else return (Database db)
 
--- | <http://www.sqlite.org/c3ref/step.html>
+-- | <https://www.sqlite.org/c3ref/step.html>
 step :: Statement -> IO (Either Error StepResult)
 step (Statement stmt) =
     toStepResult <$> c_sqlite3_step stmt
 
--- | <http://www.sqlite.org/c3ref/reset.html>
+-- | <https://www.sqlite.org/c3ref/step.html>
 --
+-- Faster step for statements that don't callback to Haskell
+-- functions (e.g. by using custom SQL functions).
+stepNoCB :: Statement -> IO (Either Error StepResult)
+stepNoCB (Statement stmt) =
+    toStepResult <$> c_sqlite3_step_unsafe stmt
+
+-- | <https://www.sqlite.org/c3ref/reset.html>
+--
 -- Warning:
 --
 --  * If the most recent 'step' call failed,
@@ -475,7 +471,7 @@
 reset (Statement stmt) =
     toResult () <$> c_sqlite3_reset stmt
 
--- | <http://www.sqlite.org/c3ref/finalize.html>
+-- | <https://www.sqlite.org/c3ref/finalize.html>
 --
 -- /Warning:/ If the most recent 'step' call failed,
 -- this will return the corresponding error.
@@ -483,14 +479,14 @@
 finalize (Statement stmt) =
     toResult () <$> c_sqlite3_finalize stmt
 
--- | <http://www.sqlite.org/c3ref/sql.html>
+-- | <https://www.sqlite.org/c3ref/sql.html>
 --
 -- Return a copy of the original SQL text used to compile the statement.
 statementSql :: Statement -> IO (Maybe Utf8)
 statementSql (Statement stmt) =
     c_sqlite3_sql stmt >>= packUtf8 Nothing Just
 
--- | <http://www.sqlite.org/c3ref/clear_bindings.html>
+-- | <https://www.sqlite.org/c3ref/clear_bindings.html>
 --
 -- Set all parameters in the prepared statement to null.
 clearBindings :: Statement -> IO ()
@@ -498,7 +494,7 @@
     _ <- c_sqlite3_clear_bindings stmt
     return ()
 
--- | <http://www.sqlite.org/c3ref/bind_parameter_count.html>
+-- | <https://www.sqlite.org/c3ref/bind_parameter_count.html>
 --
 -- This returns the index of the largest (rightmost) parameter.  Note that this
 -- is not necessarily the number of parameters.  If numbered parameters like
@@ -509,25 +505,25 @@
 bindParameterCount (Statement stmt) =
     fromFFI <$> c_sqlite3_bind_parameter_count stmt
 
--- | <http://www.sqlite.org/c3ref/bind_parameter_name.html>
+-- | <https://www.sqlite.org/c3ref/bind_parameter_name.html>
 bindParameterName :: Statement -> ParamIndex -> IO (Maybe Utf8)
 bindParameterName (Statement stmt) idx =
     c_sqlite3_bind_parameter_name stmt (toFFI idx) >>=
         packUtf8 Nothing Just
 
--- | <http://www.sqlite.org/c3ref/bind_parameter_index.html>
+-- | <https://www.sqlite.org/c3ref/bind_parameter_index.html>
 bindParameterIndex :: Statement -> Utf8 -> IO (Maybe ParamIndex)
 bindParameterIndex (Statement stmt) (Utf8 name) =
     BS.useAsCString name $ \name' -> do
         idx <- fromFFI <$> c_sqlite3_bind_parameter_index stmt name'
         return $ if idx == 0 then Nothing else Just idx
 
--- | <http://www.sqlite.org/c3ref/column_count.html>
+-- | <https://www.sqlite.org/c3ref/column_count.html>
 columnCount :: Statement -> IO ColumnCount
 columnCount (Statement stmt) =
     fromFFI <$> c_sqlite3_column_count stmt
 
--- | <http://www.sqlite.org/c3ref/column_name.html>
+-- | <https://www.sqlite.org/c3ref/column_name.html>
 columnName :: Statement -> ColumnIndex -> IO (Maybe Utf8)
 columnName (Statement stmt) idx =
     c_sqlite3_column_name stmt (toFFI idx) >>=
@@ -586,13 +582,12 @@
     len <- c_sqlite3_column_bytes stmt (toFFI idx)
     packCStringLen ptr len
 
-
--- | <http://www.sqlite.org/c3ref/last_insert_rowid.html>
+-- | <https://www.sqlite.org/c3ref/last_insert_rowid.html>
 lastInsertRowId :: Database -> IO Int64
 lastInsertRowId (Database db) =
     c_sqlite3_last_insert_rowid db
 
--- | <http://www.sqlite.org/c3ref/changes.html>
+-- | <https://www.sqlite.org/c3ref/changes.html>
 --
 -- Return the number of rows that were changed, inserted, or deleted
 -- by the most recent @INSERT@, @DELETE@, or @UPDATE@ statement.
@@ -600,7 +595,7 @@
 changes (Database db) =
     fromIntegral <$> c_sqlite3_changes db
 
--- | <http://www.sqlite.org/c3ref/total_changes.html>
+-- | <https://www.sqlite.org/c3ref/total_changes.html>
 --
 -- Return the total number of row changes caused by @INSERT@, @DELETE@,
 -- or @UPDATE@ statements since the 'Database' was opened.
@@ -628,7 +623,7 @@
         freeStablePtr p'
 {-# NOINLINE destroyCFuncPtrs #-}
 
--- | <http://sqlite.org/c3ref/create_function.html>
+-- | <https://sqlite.org/c3ref/create_function.html>
 --
 -- Create a custom SQL function or redefine the behavior of an existing
 -- function.
@@ -732,7 +727,6 @@
 maybeArgCount (Just n) = toFFI n
 maybeArgCount Nothing = -1
 
-
 funcArgCount :: FuncArgs -> ArgCount
 funcArgCount (FuncArgs nArgs _) = fromIntegral nArgs
 
@@ -768,7 +762,6 @@
         extract cval
     | otherwise = return defVal
 
-
 funcResultInt64 :: FuncContext -> Int64 -> IO ()
 funcResultInt64 (FuncContext ctx) value =
     c_sqlite3_result_int64 ctx value
@@ -803,20 +796,19 @@
         then fail $ "sqlite3_context_db_handle(" ++ show ctx ++ ") returned NULL"
         else return (Database db)
 
-
--- Deallocate the function pointer to the comparison function used to
+-- | Deallocate the function pointer to the comparison function used to
 -- implement a custom collation
 destroyCCompare :: CFuncDestroy ()
 destroyCCompare ptr = freeHaskellFunPtr ptr'
   where
     ptr' = castPtrToFunPtr ptr :: FunPtr (CCompare ())
 
--- This is called by sqlite so we create one global FunPtr to pass to sqlite
+-- | This is called by sqlite so we create one global FunPtr to pass to sqlite
 destroyCComparePtr :: FunPtr (CFuncDestroy ())
 destroyCComparePtr = IOU.unsafePerformIO $ mkCFuncDestroy destroyCCompare
 {-# NOINLINE destroyCComparePtr #-}
 
--- | <http://www.sqlite.org/c3ref/create_collation.html>
+-- | <https://www.sqlite.org/c3ref/create_collation.html>
 createCollation
     :: Database
     -> Utf8                       -- ^ Name of the collation.
@@ -846,18 +838,17 @@
 deleteCollation :: Database -> Utf8 -> IO (Either Error ())
 deleteCollation (Database db) (Utf8 name) =
     BS.useAsCString name $ \namePtr ->
-        toResult () <$> do
+        toResult () <$>
             c_sqlite3_create_collation_v2
                 db namePtr c_SQLITE_UTF8 nullPtr nullFunPtr nullFunPtr
 
--- | <http://www.sqlite.org/c3ref/enable_load_extension.html>
+-- | <https://www.sqlite.org/c3ref/enable_load_extension.html>
 --
 -- Enable or disable extension loading.
 setLoadExtensionEnabled :: Database -> Bool -> IO (Either Error ())
-setLoadExtensionEnabled (Database db) enabled = do
+setLoadExtensionEnabled (Database db) enabled =
     toResult () <$> c_sqlite3_enable_load_extension db enabled
 
-
 -- | <https://www.sqlite.org/c3ref/blob_open.html>
 --
 -- Open a blob for incremental I/O.
@@ -873,7 +864,7 @@
     BS.useAsCString zDb $ \ptrDb ->
     BS.useAsCString zTable $ \ptrTable ->
     BS.useAsCString zColumn $ \ptrColumn ->
-    alloca $ \ptrBlob -> do
+    alloca $ \ptrBlob ->
         c_sqlite3_blob_open db ptrDb ptrTable ptrColumn rowid flags ptrBlob
             >>= toResultM (Blob (Database db) <$> peek ptrBlob)
   where
@@ -885,7 +876,10 @@
     toResult () <$> c_sqlite3_blob_close blob
 
 -- | <https://www.sqlite.org/c3ref/blob_reopen.html>
-blobReopen :: Blob -> Int64 -> IO (Either Error ())
+blobReopen
+    :: Blob
+    -> Int64 -- ^ The @ROWID@ of the row.
+    -> IO (Either Error ())
 blobReopen (Blob _ blob) rowid =
     toResult () <$> c_sqlite3_blob_reopen blob rowid
 
@@ -897,23 +891,13 @@
 -- | <https://www.sqlite.org/c3ref/blob_read.html>
 blobRead
     :: Blob
-    -> Int -- ^ Number of bytes to read.
-    -> Int -- ^ Offset within the 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)
+blobRead blob len offset = do
+    fp <- BSI.mallocByteString len
+    fmap (\_ -> BSI.fromForeignPtr fp 0 len) <$>
+        withForeignPtr fp (\p -> blobReadBuf blob p len offset)
 
 blobReadBuf :: Blob -> Ptr a -> Int -> Int -> IO (Either Error ())
 blobReadBuf (Blob _ blob) buf len offset =
@@ -931,12 +915,12 @@
         toResult () <$>
             c_sqlite3_blob_write blob buf (fromIntegral len) (fromIntegral offset)
 
-
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupinit>
 backupInit
-    :: Database  -- ^ Destination database handle
-    -> Utf8      -- ^ Destination database name
-    -> Database  -- ^ Source database handle
-    -> Utf8      -- ^ Source database name
+    :: 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' ->
@@ -946,20 +930,27 @@
             then Left <$> errcode (Database dstDb)
             else return (Right (Backup (Database dstDb) r))
 
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish>
 backupFinish :: Backup -> IO (Either Error ())
 backupFinish (Backup _ backup) =
     toResult () <$>
         c_sqlite3_backup_finish backup
 
-backupStep :: Backup -> Int -> IO (Either Error BackupStepResult)
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupstep>
+backupStep
+    :: Backup
+    -> Int    -- ^ Number of pages to copy; if negative, all remaining source pages are copied.
+    -> IO (Either Error BackupStepResult)
 backupStep (Backup _ backup) pages =
     toBackupStepResult <$>
         c_sqlite3_backup_step backup (fromIntegral pages)
 
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupremaining>
 backupRemaining :: Backup -> IO Int
 backupRemaining (Backup _ backup) =
     fromIntegral <$> c_sqlite3_backup_remaining backup
 
+-- | <https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backuppagecount>
 backupPagecount :: Backup -> IO Int
 backupPagecount (Backup _ backup) =
     fromIntegral <$> c_sqlite3_backup_pagecount backup
diff --git a/cbits/sqlite3.c b/cbits/sqlite3.c
# file too large to diff: cbits/sqlite3.c
diff --git a/cbits/sqlite3.h b/cbits/sqlite3.h
--- a/cbits/sqlite3.h
+++ b/cbits/sqlite3.h
@@ -123,9 +123,9 @@
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.22.0"
-#define SQLITE_VERSION_NUMBER 3022000
-#define SQLITE_SOURCE_ID      "2018-01-22 18:45:57 0c55d179733b46d8d0ba4d88e01a25e10677046ee3da1d5b1581e86726f2171d"
+#define SQLITE_VERSION        "3.24.0"
+#define SQLITE_VERSION_NUMBER 3024000
+#define SQLITE_SOURCE_ID      "2018-06-04 19:24:41 c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199a87ca"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -504,6 +504,7 @@
 #define SQLITE_IOERR_COMMIT_ATOMIC     (SQLITE_IOERR | (30<<8))
 #define SQLITE_IOERR_ROLLBACK_ATOMIC   (SQLITE_IOERR | (31<<8))
 #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
+#define SQLITE_LOCKED_VTAB             (SQLITE_LOCKED |  (2<<8))
 #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
 #define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
 #define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
@@ -511,6 +512,7 @@
 #define SQLITE_CANTOPEN_FULLPATH       (SQLITE_CANTOPEN | (3<<8))
 #define SQLITE_CANTOPEN_CONVPATH       (SQLITE_CANTOPEN | (4<<8))
 #define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
+#define SQLITE_CORRUPT_SEQUENCE        (SQLITE_CORRUPT | (2<<8))
 #define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
 #define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
 #define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
@@ -1064,6 +1066,12 @@
 ** so that all subsequent write operations are independent.
 ** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
 ** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
+**
+** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
+** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode causes attempts to obtain
+** a file lock using the xLock or xShmLock methods of the VFS to wait
+** for up to M milliseconds before failing, where M is the single 
+** unsigned integer parameter.
 ** </ul>
 */
 #define SQLITE_FCNTL_LOCKSTATE               1
@@ -1098,6 +1106,7 @@
 #define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
 #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
+#define SQLITE_FCNTL_LOCK_TIMEOUT           34
 
 /* deprecated names */
 #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1923,6 +1932,22 @@
 ** I/O required to support statement rollback.
 ** The default value for this setting is controlled by the
 ** [SQLITE_STMTJRNL_SPILL] compile-time option.
+**
+** [[SQLITE_CONFIG_SORTERREF_SIZE]]
+** <dt>SQLITE_CONFIG_SORTERREF_SIZE
+** <dd>The SQLITE_CONFIG_SORTERREF_SIZE option accepts a single parameter
+** of type (int) - the new value of the sorter-reference size threshold.
+** Usually, when SQLite uses an external sort to order records according
+** to an ORDER BY clause, all fields required by the caller are present in the
+** sorted records. However, if SQLite determines based on the declared type
+** of a table column that its values are likely to be very large - larger
+** than the configured sorter-reference size threshold - then a reference
+** is stored in each sorted record and the required column values loaded
+** from the database as records are returned in sorted order. The default
+** value for this option is to never use this optimization. Specifying a 
+** negative value for this option restores the default behaviour.
+** This option is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
 ** </dl>
 */
 #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
@@ -1952,6 +1977,7 @@
 #define SQLITE_CONFIG_PMASZ               25  /* unsigned int szPma */
 #define SQLITE_CONFIG_STMTJRNL_SPILL      26  /* int nByte */
 #define SQLITE_CONFIG_SMALL_MALLOC        27  /* boolean */
+#define SQLITE_CONFIG_SORTERREF_SIZE      28  /* int nByte */
 
 /*
 ** CAPI3REF: Database Connection Configuration Options
@@ -2054,11 +2080,13 @@
 ** connections at all to the database. If so, it performs a checkpoint 
 ** operation before closing the connection. This option may be used to
 ** override this behaviour. The first parameter passed to this operation
-** is an integer - non-zero to disable checkpoints-on-close, or zero (the
-** default) to enable them. The second parameter is a pointer to an integer
+** is an integer - positive to disable checkpoints-on-close, or zero (the
+** default) to enable them, and negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer
 ** into which is written 0 or 1 to indicate whether checkpoints-on-close
 ** have been disabled - 0 if they are not disabled, 1 if they are.
 ** </dd>
+**
 ** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
 ** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates
 ** the [query planner stability guarantee] (QPSG).  When the QPSG is active,
@@ -2068,17 +2096,39 @@
 ** slower.  But the QPSG has the advantage of more predictable behavior.  With
 ** the QPSG active, SQLite will always use the same query plan in the field as
 ** was used during testing in the lab.
+** The first argument to this setting is an integer which is 0 to disable 
+** the QPSG, positive to enable QPSG, or negative to leave the setting
+** unchanged. The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether the QPSG is disabled or enabled
+** following this call.
 ** </dd>
+**
 ** <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
 ** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not 
 ** include output for any operations performed by trigger programs. This
 ** option is used to set or clear (the default) a flag that governs this
 ** behavior. The first parameter passed to this operation is an integer -
-** non-zero to enable output for trigger programs, or zero to disable it.
+** positive to enable output for trigger programs, or zero to disable it,
+** or negative to leave the setting unchanged.
 ** The second parameter is a pointer to an integer into which is written 
 ** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if 
 ** it is not disabled, 1 if it is.  
 ** </dd>
+**
+** <dt>SQLITE_DBCONFIG_RESET_DATABASE</dt>
+** <dd> Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run
+** [VACUUM] in order to reset a database back to an empty database
+** with no schema and no content. The following process works even for
+** a badly corrupted database file:
+** <ol>
+** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
+** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
+** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
+** </ol>
+** Because resetting a database is destructive and irreversible, the
+** process requires the use of this obscure API and multiple steps to help
+** ensure that it does not happen by accident.
+** </dd>
 ** </dl>
 */
 #define SQLITE_DBCONFIG_MAINDBNAME            1000 /* const char* */
@@ -2090,7 +2140,8 @@
 #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE      1006 /* int int* */
 #define SQLITE_DBCONFIG_ENABLE_QPSG           1007 /* int int* */
 #define SQLITE_DBCONFIG_TRIGGER_EQP           1008 /* int int* */
-#define SQLITE_DBCONFIG_MAX                   1008 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_RESET_DATABASE        1009 /* int int* */
+#define SQLITE_DBCONFIG_MAX                   1009 /* Largest DBCONFIG */
 
 /*
 ** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2496,16 +2547,16 @@
 **
 ** These routines are work-alikes of the "printf()" family of functions
 ** from the standard C library.
-** These routines understand most of the common K&R formatting options,
-** plus some additional non-standard formats, detailed below.
-** Note that some of the more obscure formatting options from recent
-** C-library standards are omitted from this implementation.
+** These routines understand most of the common formatting options from
+** the standard library printf() 
+** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]).
+** See the [built-in printf()] documentation for details.
 **
 ** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
-** results into memory obtained from [sqlite3_malloc()].
+** results into memory obtained from [sqlite3_malloc64()].
 ** The strings returned by these two routines should be
 ** released by [sqlite3_free()].  ^Both routines return a
-** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
+** NULL pointer if [sqlite3_malloc64()] is unable to allocate enough
 ** memory to hold the resulting string.
 **
 ** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
@@ -2529,71 +2580,7 @@
 **
 ** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
 **
-** These routines all implement some additional formatting
-** options that are useful for constructing SQL statements.
-** All of the usual printf() formatting options apply.  In addition, there
-** is are "%q", "%Q", "%w" and "%z" options.
-**
-** ^(The %q option works like %s in that it substitutes a nul-terminated
-** string from the argument list.  But %q also doubles every '\'' character.
-** %q is designed for use inside a string literal.)^  By doubling each '\''
-** character it escapes that character and allows it to be inserted into
-** the string.
-**
-** For example, assume the string variable zText contains text as follows:
-**
-** <blockquote><pre>
-**  char *zText = "It's a happy day!";
-** </pre></blockquote>
-**
-** One can use this text in an SQL statement as follows:
-**
-** <blockquote><pre>
-**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
-**  sqlite3_exec(db, zSQL, 0, 0, 0);
-**  sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** Because the %q format string is used, the '\'' character in zText
-** is escaped and the SQL generated is as follows:
-**
-** <blockquote><pre>
-**  INSERT INTO table1 VALUES('It''s a happy day!')
-** </pre></blockquote>
-**
-** This is correct.  Had we used %s instead of %q, the generated SQL
-** would have looked like this:
-**
-** <blockquote><pre>
-**  INSERT INTO table1 VALUES('It's a happy day!');
-** </pre></blockquote>
-**
-** This second example is an SQL syntax error.  As a general rule you should
-** always use %q instead of %s when inserting text into a string literal.
-**
-** ^(The %Q option works like %q except it also adds single quotes around
-** the outside of the total string.  Additionally, if the parameter in the
-** argument list is a NULL pointer, %Q substitutes the text "NULL" (without
-** single quotes).)^  So, for example, one could say:
-**
-** <blockquote><pre>
-**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
-**  sqlite3_exec(db, zSQL, 0, 0, 0);
-**  sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** The code above will render a correct SQL statement in the zSQL
-** variable even if the zText variable is a NULL pointer.
-**
-** ^(The "%w" formatting option is like "%q" except that it expects to
-** be contained within double-quotes instead of single quotes, and it
-** escapes the double-quote character instead of the single-quote
-** character.)^  The "%w" formatting option is intended for safely inserting
-** table and column names into a constructed SQL statement.
-**
-** ^(The "%z" formatting option works like "%s" but with the
-** addition that after the string has been read and copied into
-** the result, [sqlite3_free()] is called on the input string.)^
+** See also:  [built-in printf()], [printf() SQL function]
 */
 SQLITE_API char *sqlite3_mprintf(const char*,...);
 SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
@@ -3659,13 +3646,13 @@
 ** or [GLOB] operator or if the parameter is compared to an indexed column
 ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
 ** </li>
+** </ol>
 **
 ** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
 ** the extra prepFlags parameter, which is a bit array consisting of zero or
 ** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags.  ^The
 ** sqlite3_prepare_v2() interface works exactly the same as
 ** sqlite3_prepare_v3() with a zero prepFlags parameter.
-** </ol>
 */
 SQLITE_API int sqlite3_prepare(
   sqlite3 *db,            /* Database handle */
@@ -5541,6 +5528,41 @@
 SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory;
 
 /*
+** CAPI3REF: Win32 Specific Interface
+**
+** These interfaces are available only on Windows.  The
+** [sqlite3_win32_set_directory] interface is used to set the value associated
+** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to
+** zValue, depending on the value of the type parameter.  The zValue parameter
+** should be NULL to cause the previous value to be freed via [sqlite3_free];
+** a non-NULL value will be copied into memory obtained from [sqlite3_malloc]
+** prior to being used.  The [sqlite3_win32_set_directory] interface returns
+** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported,
+** or [SQLITE_NOMEM] if memory could not be allocated.  The value of the
+** [sqlite3_data_directory] variable is intended to act as a replacement for
+** the current directory on the sub-platforms of Win32 where that concept is
+** not present, e.g. WinRT and UWP.  The [sqlite3_win32_set_directory8] and
+** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the
+** sqlite3_win32_set_directory interface except the string parameter must be
+** UTF-8 or UTF-16, respectively.
+*/
+SQLITE_API int sqlite3_win32_set_directory(
+  unsigned long type, /* Identifier for directory being set or reset */
+  void *zValue        /* New value for directory being set or reset */
+);
+SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue);
+SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue);
+
+/*
+** CAPI3REF: Win32 Directory Types
+**
+** These macros are only available on Windows.  They define the allowed values
+** for the type argument to the [sqlite3_win32_set_directory] interface.
+*/
+#define SQLITE_WIN32_DATA_DIRECTORY_TYPE  1
+#define SQLITE_WIN32_TEMP_DIRECTORY_TYPE  2
+
+/*
 ** CAPI3REF: Test For Auto-Commit Mode
 ** KEYWORDS: {autocommit mode}
 ** METHOD: sqlite3
@@ -6272,6 +6294,10 @@
 
 /*
 ** CAPI3REF: Virtual Table Scan Flags
+**
+** Virtual table implementations are allowed to set the 
+** [sqlite3_index_info].idxFlags field to some combination of
+** these bits.
 */
 #define SQLITE_INDEX_SCAN_UNIQUE      1     /* Scan visits at most 1 row */
 
@@ -7047,7 +7073,7 @@
 #define SQLITE_TESTCTRL_ALWAYS                  13
 #define SQLITE_TESTCTRL_RESERVE                 14
 #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
-#define SQLITE_TESTCTRL_ISKEYWORD               16
+#define SQLITE_TESTCTRL_ISKEYWORD               16  /* NOT USED */
 #define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
 #define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
 #define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
@@ -7062,6 +7088,189 @@
 #define SQLITE_TESTCTRL_LAST                    26  /* Largest TESTCTRL */
 
 /*
+** CAPI3REF: SQL Keyword Checking
+**
+** These routines provide access to the set of SQL language keywords 
+** recognized by SQLite.  Applications can uses these routines to determine
+** whether or not a specific identifier needs to be escaped (for example,
+** by enclosing in double-quotes) so as not to confuse the parser.
+**
+** The sqlite3_keyword_count() interface returns the number of distinct
+** keywords understood by SQLite.
+**
+** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and
+** makes *Z point to that keyword expressed as UTF8 and writes the number
+** of bytes in the keyword into *L.  The string that *Z points to is not
+** zero-terminated.  The sqlite3_keyword_name(N,Z,L) routine returns
+** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z
+** or L are NULL or invalid pointers then calls to
+** sqlite3_keyword_name(N,Z,L) result in undefined behavior.
+**
+** The sqlite3_keyword_check(Z,L) interface checks to see whether or not
+** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero
+** if it is and zero if not.
+**
+** The parser used by SQLite is forgiving.  It is often possible to use
+** a keyword as an identifier as long as such use does not result in a
+** parsing ambiguity.  For example, the statement
+** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and
+** creates a new table named "BEGIN" with three columns named
+** "REPLACE", "PRAGMA", and "END".  Nevertheless, best practice is to avoid
+** using keywords as identifiers.  Common techniques used to avoid keyword
+** name collisions include:
+** <ul>
+** <li> Put all identifier names inside double-quotes.  This is the official
+**      SQL way to escape identifier names.
+** <li> Put identifier names inside &#91;...&#93;.  This is not standard SQL,
+**      but it is what SQL Server does and so lots of programmers use this
+**      technique.
+** <li> Begin every identifier with the letter "Z" as no SQL keywords start
+**      with "Z".
+** <li> Include a digit somewhere in every identifier name.
+** </ul>
+**
+** Note that the number of keywords understood by SQLite can depend on
+** compile-time options.  For example, "VACUUM" is not a keyword if
+** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option.  Also,
+** new keywords may be added to future releases of SQLite.
+*/
+SQLITE_API int sqlite3_keyword_count(void);
+SQLITE_API int sqlite3_keyword_name(int,const char**,int*);
+SQLITE_API int sqlite3_keyword_check(const char*,int);
+
+/*
+** CAPI3REF: Dynamic String Object
+** KEYWORDS: {dynamic string}
+**
+** An instance of the sqlite3_str object contains a dynamically-sized
+** string under construction.
+**
+** The lifecycle of an sqlite3_str object is as follows:
+** <ol>
+** <li> ^The sqlite3_str object is created using [sqlite3_str_new()].
+** <li> ^Text is appended to the sqlite3_str object using various
+** methods, such as [sqlite3_str_appendf()].
+** <li> ^The sqlite3_str object is destroyed and the string it created
+** is returned using the [sqlite3_str_finish()] interface.
+** </ol>
+*/
+typedef struct sqlite3_str sqlite3_str;
+
+/*
+** CAPI3REF: Create A New Dynamic String Object
+** CONSTRUCTOR: sqlite3_str
+**
+** ^The [sqlite3_str_new(D)] interface allocates and initializes
+** a new [sqlite3_str] object.  To avoid memory leaks, the object returned by
+** [sqlite3_str_new()] must be freed by a subsequent call to 
+** [sqlite3_str_finish(X)].
+**
+** ^The [sqlite3_str_new(D)] interface always returns a pointer to a
+** valid [sqlite3_str] object, though in the event of an out-of-memory
+** error the returned object might be a special singleton that will
+** silently reject new text, always return SQLITE_NOMEM from 
+** [sqlite3_str_errcode()], always return 0 for 
+** [sqlite3_str_length()], and always return NULL from
+** [sqlite3_str_finish(X)].  It is always safe to use the value
+** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter
+** to any of the other [sqlite3_str] methods.
+**
+** The D parameter to [sqlite3_str_new(D)] may be NULL.  If the
+** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum
+** length of the string contained in the [sqlite3_str] object will be
+** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead
+** of [SQLITE_MAX_LENGTH].
+*/
+SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*);
+
+/*
+** CAPI3REF: Finalize A Dynamic String
+** DESTRUCTOR: sqlite3_str
+**
+** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X
+** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()]
+** that contains the constructed string.  The calling application should
+** pass the returned value to [sqlite3_free()] to avoid a memory leak.
+** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any
+** errors were encountered during construction of the string.  ^The
+** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the
+** string in [sqlite3_str] object X is zero bytes long.
+*/
+SQLITE_API char *sqlite3_str_finish(sqlite3_str*);
+
+/*
+** CAPI3REF: Add Content To A Dynamic String
+** METHOD: sqlite3_str
+**
+** These interfaces add content to an sqlite3_str object previously obtained
+** from [sqlite3_str_new()].
+**
+** ^The [sqlite3_str_appendf(X,F,...)] and 
+** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf]
+** functionality of SQLite to append formatted text onto the end of 
+** [sqlite3_str] object X.
+**
+** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S
+** onto the end of the [sqlite3_str] object X.  N must be non-negative.
+** S must contain at least N non-zero bytes of content.  To append a
+** zero-terminated string in its entirety, use the [sqlite3_str_appendall()]
+** method instead.
+**
+** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of
+** zero-terminated string S onto the end of [sqlite3_str] object X.
+**
+** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the
+** single-byte character C onto the end of [sqlite3_str] object X.
+** ^This method can be used, for example, to add whitespace indentation.
+**
+** ^The [sqlite3_str_reset(X)] method resets the string under construction
+** inside [sqlite3_str] object X back to zero bytes in length.  
+**
+** These methods do not return a result code.  ^If an error occurs, that fact
+** is recorded in the [sqlite3_str] object and can be recovered by a
+** subsequent call to [sqlite3_str_errcode(X)].
+*/
+SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...);
+SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list);
+SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N);
+SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn);
+SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C);
+SQLITE_API void sqlite3_str_reset(sqlite3_str*);
+
+/*
+** CAPI3REF: Status Of A Dynamic String
+** METHOD: sqlite3_str
+**
+** These interfaces return the current status of an [sqlite3_str] object.
+**
+** ^If any prior errors have occurred while constructing the dynamic string
+** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return
+** an appropriate error code.  ^The [sqlite3_str_errcode(X)] method returns
+** [SQLITE_NOMEM] following any out-of-memory error, or
+** [SQLITE_TOOBIG] if the size of the dynamic string exceeds
+** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors.
+**
+** ^The [sqlite3_str_length(X)] method returns the current length, in bytes,
+** of the dynamic string under construction in [sqlite3_str] object X.
+** ^The length returned by [sqlite3_str_length(X)] does not include the
+** zero-termination byte.
+**
+** ^The [sqlite3_str_value(X)] method returns a pointer to the current
+** content of the dynamic string under construction in X.  The value
+** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X
+** and might be freed or altered by any subsequent method on the same
+** [sqlite3_str] object.  Applications must not used the pointer returned
+** [sqlite3_str_value(X)] after any subsequent method call on the same
+** object.  ^Applications may change the content of the string returned
+** by [sqlite3_str_value(X)] as long as they do not write into any bytes
+** outside the range of 0 to [sqlite3_str_length(X)] and do not read or
+** write any byte after any subsequent sqlite3_str method call.
+*/
+SQLITE_API int sqlite3_str_errcode(sqlite3_str*);
+SQLITE_API int sqlite3_str_length(sqlite3_str*);
+SQLITE_API char *sqlite3_str_value(sqlite3_str*);
+
+/*
 ** CAPI3REF: SQLite Runtime Status
 **
 ** ^These interfaces are used to retrieve runtime status information
@@ -7294,6 +7503,15 @@
 ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
 ** </dd>
 **
+** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt>
+** <dd>This parameter returns the number of dirty cache entries that have
+** been written to disk in the middle of a transaction due to the page
+** cache overflowing. Transactions are more efficient if they are written
+** to disk all at once. When pages spill mid-transaction, that introduces
+** additional overhead. This parameter can be used help identify
+** inefficiencies that can be resolve by increasing the cache size.
+** </dd>
+**
 ** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
 ** <dd>This parameter returns zero for the current value if and only if
 ** all foreign key constraints (deferred or immediate) have been
@@ -7313,7 +7531,8 @@
 #define SQLITE_DBSTATUS_CACHE_WRITE          9
 #define SQLITE_DBSTATUS_DEFERRED_FKS        10
 #define SQLITE_DBSTATUS_CACHE_USED_SHARED   11
-#define SQLITE_DBSTATUS_MAX                 11   /* Largest defined DBSTATUS */
+#define SQLITE_DBSTATUS_CACHE_SPILL         12
+#define SQLITE_DBSTATUS_MAX                 12   /* Largest defined DBSTATUS */
 
 
 /*
@@ -8320,11 +8539,11 @@
 ** method of a [virtual table], then it returns true if and only if the
 ** column is being fetched as part of an UPDATE operation during which the
 ** column value will not change.  Applications might use this to substitute
-** a lighter-weight value to return that the corresponding [xUpdate] method
-** understands as a "no-change" value.
+** a return value that is less expensive to compute and that the corresponding
+** [xUpdate] method understands as a "no-change" value.
 **
 ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
-** the column is not changed by the UPDATE statement, they the xColumn
+** the column is not changed by the UPDATE statement, then the xColumn
 ** method can optionally return without setting a result, without calling
 ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
 ** In that case, [sqlite3_value_nochange(X)] will return true for the
@@ -8794,6 +9013,128 @@
 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
 
 /*
+** CAPI3REF: Serialize a database
+**
+** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory
+** that is a serialization of the S database on [database connection] D.
+** If P is not a NULL pointer, then the size of the database in bytes
+** is written into *P.
+**
+** For an ordinary on-disk database file, the serialization is just a
+** copy of the disk file.  For an in-memory database or a "TEMP" database,
+** the serialization is the same sequence of bytes which would be written
+** to disk if that database where backed up to disk.
+**
+** The usual case is that sqlite3_serialize() copies the serialization of
+** the database into memory obtained from [sqlite3_malloc64()] and returns
+** a pointer to that memory.  The caller is responsible for freeing the
+** returned value to avoid a memory leak.  However, if the F argument
+** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations
+** are made, and the sqlite3_serialize() function will return a pointer
+** to the contiguous memory representation of the database that SQLite
+** is currently using for that database, or NULL if the no such contiguous
+** memory representation of the database exists.  A contiguous memory
+** representation of the database will usually only exist if there has
+** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
+** values of D and S.
+** The size of the database is written into *P even if the 
+** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
+** of the database exists.
+**
+** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the
+** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
+** allocation error occurs.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_DESERIALIZE] option.
+*/
+SQLITE_API unsigned char *sqlite3_serialize(
+  sqlite3 *db,           /* The database connection */
+  const char *zSchema,   /* Which DB to serialize. ex: "main", "temp", ... */
+  sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */
+  unsigned int mFlags    /* Zero or more SQLITE_SERIALIZE_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3_serialize
+**
+** Zero or more of the following constants can be OR-ed together for
+** the F argument to [sqlite3_serialize(D,S,P,F)].
+**
+** SQLITE_SERIALIZE_NOCOPY means that [sqlite3_serialize()] will return
+** a pointer to contiguous in-memory database that it is currently using,
+** without making a copy of the database.  If SQLite is not currently using
+** a contiguous in-memory database, then this option causes
+** [sqlite3_serialize()] to return a NULL pointer.  SQLite will only be
+** using a contiguous in-memory database if it has been initialized by a
+** prior call to [sqlite3_deserialize()].
+*/
+#define SQLITE_SERIALIZE_NOCOPY 0x001   /* Do no memory allocations */
+
+/*
+** CAPI3REF: Deserialize a database
+**
+** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the 
+** [database connection] D to disconnect from database S and then
+** reopen S as an in-memory database based on the serialization contained
+** in P.  The serialized database P is N bytes in size.  M is the size of
+** the buffer P, which might be larger than N.  If M is larger than N, and
+** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is
+** permitted to add content to the in-memory database as long as the total
+** size does not exceed M bytes.
+**
+** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will
+** invoke sqlite3_free() on the serialization buffer when the database
+** connection closes.  If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then
+** SQLite will try to increase the buffer size using sqlite3_realloc64()
+** if writes on the database cause it to grow larger than M bytes.
+**
+** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
+** database is currently in a read transaction or is involved in a backup
+** operation.
+**
+** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the 
+** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
+** [sqlite3_free()] is invoked on argument P prior to returning.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_DESERIALIZE] option.
+*/
+SQLITE_API int sqlite3_deserialize(
+  sqlite3 *db,            /* The database connection */
+  const char *zSchema,    /* Which DB to reopen with the deserialization */
+  unsigned char *pData,   /* The serialized database content */
+  sqlite3_int64 szDb,     /* Number bytes in the deserialization */
+  sqlite3_int64 szBuf,    /* Total size of buffer pData[] */
+  unsigned mFlags         /* Zero or more SQLITE_DESERIALIZE_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3_deserialize()
+**
+** The following are allowed values for 6th argument (the F argument) to
+** the [sqlite3_deserialize(D,S,P,N,M,F)] interface.
+**
+** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization
+** in the P argument is held in memory obtained from [sqlite3_malloc64()]
+** and that SQLite should take ownership of this memory and automatically
+** free it when it has finished using it.  Without this flag, the caller
+** is resposible for freeing any dynamically allocated memory.
+**
+** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to
+** grow the size of the database using calls to [sqlite3_realloc64()].  This
+** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used.
+** Without this flag, the deserialized database cannot increase in size beyond
+** the number of bytes specified by the M parameter.
+**
+** The SQLITE_DESERIALIZE_READONLY flag means that the deserialized database
+** should be treated as read-only.
+*/
+#define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */
+#define SQLITE_DESERIALIZE_RESIZEABLE  2 /* Resize using sqlite3_realloc64() */
+#define SQLITE_DESERIALIZE_READONLY    4 /* Database is read-only */
+
+/*
 ** Undo the hack that converts floating point types to integer for
 ** builds on processors without floating point support.
 */
@@ -8940,16 +9281,23 @@
 
 /*
 ** CAPI3REF: Session Object Handle
+**
+** An instance of this object is a [session] that can be used to
+** record changes to a database.
 */
 typedef struct sqlite3_session sqlite3_session;
 
 /*
 ** CAPI3REF: Changeset Iterator Handle
+**
+** An instance of this object acts as a cursor for iterating
+** over the elements of a [changeset] or [patchset].
 */
 typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
 
 /*
 ** CAPI3REF: Create A New Session Object
+** CONSTRUCTOR: sqlite3_session
 **
 ** Create a new session object attached to database handle db. If successful,
 ** a pointer to the new object is written to *ppSession and SQLITE_OK is
@@ -8986,6 +9334,7 @@
 
 /*
 ** CAPI3REF: Delete A Session Object
+** DESTRUCTOR: sqlite3_session
 **
 ** Delete a session object previously allocated using 
 ** [sqlite3session_create()]. Once a session object has been deleted, the
@@ -9001,6 +9350,7 @@
 
 /*
 ** CAPI3REF: Enable Or Disable A Session Object
+** METHOD: sqlite3_session
 **
 ** Enable or disable the recording of changes by a session object. When
 ** enabled, a session object records changes made to the database. When
@@ -9020,6 +9370,7 @@
 
 /*
 ** CAPI3REF: Set Or Clear the Indirect Change Flag
+** METHOD: sqlite3_session
 **
 ** Each change recorded by a session object is marked as either direct or
 ** indirect. A change is marked as indirect if either:
@@ -9049,6 +9400,7 @@
 
 /*
 ** CAPI3REF: Attach A Table To A Session Object
+** METHOD: sqlite3_session
 **
 ** If argument zTab is not NULL, then it is the name of a table to attach
 ** to the session object passed as the first argument. All subsequent changes 
@@ -9111,6 +9463,7 @@
 
 /*
 ** CAPI3REF: Set a table filter on a Session Object.
+** METHOD: sqlite3_session
 **
 ** The second argument (xFilter) is the "filter callback". For changes to rows 
 ** in tables that are not attached to the Session object, the filter is called
@@ -9129,6 +9482,7 @@
 
 /*
 ** CAPI3REF: Generate A Changeset From A Session Object
+** METHOD: sqlite3_session
 **
 ** Obtain a changeset containing changes to the tables attached to the 
 ** session object passed as the first argument. If successful, 
@@ -9238,7 +9592,8 @@
 );
 
 /*
-** CAPI3REF: Load The Difference Between Tables Into A Session 
+** CAPI3REF: Load The Difference Between Tables Into A Session
+** METHOD: sqlite3_session
 **
 ** If it is not already attached to the session object passed as the first
 ** argument, this function attaches table zTbl in the same manner as the
@@ -9303,6 +9658,7 @@
 
 /*
 ** CAPI3REF: Generate A Patchset From A Session Object
+** METHOD: sqlite3_session
 **
 ** The differences between a patchset and a changeset are that:
 **
@@ -9354,6 +9710,7 @@
 
 /*
 ** CAPI3REF: Create An Iterator To Traverse A Changeset 
+** CONSTRUCTOR: sqlite3_changeset_iter
 **
 ** Create an iterator used to iterate through the contents of a changeset.
 ** If successful, *pp is set to point to the iterator handle and SQLITE_OK
@@ -9394,6 +9751,7 @@
 
 /*
 ** CAPI3REF: Advance A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
 **
 ** This function may only be used with iterators created by function
 ** [sqlite3changeset_start()]. If it is called on an iterator passed to
@@ -9418,6 +9776,7 @@
 
 /*
 ** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
 **
 ** The pIter argument passed to this function may either be an iterator
 ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
@@ -9452,6 +9811,7 @@
 
 /*
 ** CAPI3REF: Obtain The Primary Key Definition Of A Table
+** METHOD: sqlite3_changeset_iter
 **
 ** For each modified table, a changeset includes the following:
 **
@@ -9483,6 +9843,7 @@
 
 /*
 ** CAPI3REF: Obtain old.* Values From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
 **
 ** The pIter argument passed to this function may either be an iterator
 ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
@@ -9513,6 +9874,7 @@
 
 /*
 ** CAPI3REF: Obtain new.* Values From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
 **
 ** The pIter argument passed to this function may either be an iterator
 ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
@@ -9546,6 +9908,7 @@
 
 /*
 ** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
 **
 ** This function should only be used with iterator objects passed to a
 ** conflict-handler callback by [sqlite3changeset_apply()] with either
@@ -9573,6 +9936,7 @@
 
 /*
 ** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
+** METHOD: sqlite3_changeset_iter
 **
 ** This function may only be called with an iterator passed to an
 ** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
@@ -9589,6 +9953,7 @@
 
 /*
 ** CAPI3REF: Finalize A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
 **
 ** This function is used to finalize an iterator allocated with
 ** [sqlite3changeset_start()].
@@ -9605,6 +9970,7 @@
 ** to that error is returned by this function. Otherwise, SQLITE_OK is
 ** returned. This is to allow the following pattern (pseudo-code):
 **
+** <pre>
 **   sqlite3changeset_start();
 **   while( SQLITE_ROW==sqlite3changeset_next() ){
 **     // Do something with change.
@@ -9613,6 +9979,7 @@
 **   if( rc!=SQLITE_OK ){
 **     // An error has occurred 
 **   }
+** </pre>
 */
 SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
 
@@ -9660,6 +10027,7 @@
 ** sqlite3_changegroup object. Calling it produces similar results as the
 ** following code fragment:
 **
+** <pre>
 **   sqlite3_changegroup *pGrp;
 **   rc = sqlite3_changegroup_new(&pGrp);
 **   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
@@ -9670,6 +10038,7 @@
 **     *ppOut = 0;
 **     *pnOut = 0;
 **   }
+** </pre>
 **
 ** Refer to the sqlite3_changegroup documentation below for details.
 */
@@ -9685,11 +10054,15 @@
 
 /*
 ** CAPI3REF: Changegroup Handle
+**
+** A changegroup is an object used to combine two or more 
+** [changesets] or [patchsets]
 */
 typedef struct sqlite3_changegroup sqlite3_changegroup;
 
 /*
 ** CAPI3REF: Create A New Changegroup Object
+** CONSTRUCTOR: sqlite3_changegroup
 **
 ** An sqlite3_changegroup object is used to combine two or more changesets
 ** (or patchsets) into a single changeset (or patchset). A single changegroup
@@ -9727,6 +10100,7 @@
 
 /*
 ** CAPI3REF: Add A Changeset To A Changegroup
+** METHOD: sqlite3_changegroup
 **
 ** Add all changes within the changeset (or patchset) in buffer pData (size
 ** nData bytes) to the changegroup. 
@@ -9804,6 +10178,7 @@
 
 /*
 ** CAPI3REF: Obtain A Composite Changeset From A Changegroup
+** METHOD: sqlite3_changegroup
 **
 ** Obtain a buffer containing a changeset (or patchset) representing the
 ** current contents of the changegroup. If the inputs to the changegroup
@@ -9834,25 +10209,25 @@
 
 /*
 ** CAPI3REF: Delete A Changegroup Object
+** DESTRUCTOR: sqlite3_changegroup
 */
 SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
 
 /*
 ** CAPI3REF: Apply A Changeset To A Database
 **
-** Apply a changeset to a database. This function attempts to update the
-** "main" database attached to handle db with the changes found in the
-** changeset passed via the second and third arguments.
+** Apply a changeset or patchset to a database. These functions attempt to
+** update the "main" database attached to handle db with the changes found in
+** the changeset passed via the second and third arguments. 
 **
-** The fourth argument (xFilter) passed to this function is the "filter
+** The fourth argument (xFilter) passed to these functions is the "filter
 ** callback". If it is not NULL, then for each table affected by at least one
 ** change in the changeset, the filter callback is invoked with
 ** the table name as the second argument, and a copy of the context pointer
-** passed as the sixth argument to this function as the first. If the "filter
-** callback" returns zero, then no attempt is made to apply any changes to 
-** the table. Otherwise, if the return value is non-zero or the xFilter
-** argument to this function is NULL, all changes related to the table are
-** attempted.
+** passed as the sixth argument as the first. If the "filter callback"
+** returns zero, then no attempt is made to apply any changes to the table.
+** Otherwise, if the return value is non-zero or the xFilter argument to
+** is NULL, all changes related to the table are attempted.
 **
 ** For each table that is not excluded by the filter callback, this function 
 ** tests that the target database contains a compatible table. A table is 
@@ -9897,7 +10272,7 @@
 **
 ** <dl>
 ** <dt>DELETE Changes<dd>
-**   For each DELETE change, this function checks if the target database 
+**   For each DELETE change, the function checks if the target database 
 **   contains a row with the same primary key value (or values) as the 
 **   original row values stored in the changeset. If it does, and the values 
 **   stored in all non-primary key columns also match the values stored in 
@@ -9942,7 +10317,7 @@
 **   [SQLITE_CHANGESET_REPLACE].
 **
 ** <dt>UPDATE Changes<dd>
-**   For each UPDATE change, this function checks if the target database 
+**   For each UPDATE change, the function checks if the target database 
 **   contains a row with the same primary key value (or values) as the 
 **   original row values stored in the changeset. If it does, and the values 
 **   stored in all modified non-primary key columns also match the values
@@ -9973,11 +10348,28 @@
 ** This can be used to further customize the applications conflict
 ** resolution strategy.
 **
-** All changes made by this function are enclosed in a savepoint transaction.
+** All changes made by these functions are enclosed in a savepoint transaction.
 ** If any other error (aside from a constraint failure when attempting to
 ** write to the target database) occurs, then the savepoint transaction is
 ** rolled back, restoring the target database to its original state, and an 
 ** SQLite error code returned.
+**
+** If the output parameters (ppRebase) and (pnRebase) are non-NULL and
+** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2()
+** may set (*ppRebase) to point to a "rebase" that may be used with the 
+** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase)
+** is set to the size of the buffer in bytes. It is the responsibility of the
+** caller to eventually free any such buffer using sqlite3_free(). The buffer
+** is only allocated and populated if one or more conflicts were encountered
+** while applying the patchset. See comments surrounding the sqlite3_rebaser
+** APIs for further details.
+**
+** The behavior of sqlite3changeset_apply_v2() and its streaming equivalent
+** may be modified by passing a combination of
+** [SQLITE_CHANGESETAPPLY_NOSAVEPOINT | supported flags] as the 9th parameter.
+**
+** Note that the sqlite3changeset_apply_v2() API is still <b>experimental</b>
+** and therefore subject to change.
 */
 SQLITE_API int sqlite3changeset_apply(
   sqlite3 *db,                    /* Apply change to "main" db of this handle */
@@ -9994,7 +10386,42 @@
   ),
   void *pCtx                      /* First argument passed to xConflict */
 );
+SQLITE_API int sqlite3changeset_apply_v2(
+  sqlite3 *db,                    /* Apply change to "main" db of this handle */
+  int nChangeset,                 /* Size of changeset in bytes */
+  void *pChangeset,               /* Changeset blob */
+  int(*xFilter)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    const char *zTab              /* Table name */
+  ),
+  int(*xConflict)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
+    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
+  ),
+  void *pCtx,                     /* First argument passed to xConflict */
+  void **ppRebase, int *pnRebase, /* OUT: Rebase data */
+  int flags                       /* Combination of SESSION_APPLY_* flags */
+);
 
+/*
+** CAPI3REF: Flags for sqlite3changeset_apply_v2
+**
+** The following flags may passed via the 9th parameter to
+** [sqlite3changeset_apply_v2] and [sqlite3changeset_apply_v2_strm]:
+**
+** <dl>
+** <dt>SQLITE_CHANGESETAPPLY_NOSAVEPOINT <dd>
+**   Usually, the sessions module encloses all operations performed by
+**   a single call to apply_v2() or apply_v2_strm() in a [SAVEPOINT]. The
+**   SAVEPOINT is committed if the changeset or patchset is successfully
+**   applied, or rolled back if an error occurs. Specifying this flag
+**   causes the sessions module to omit this savepoint. In this case, if the
+**   caller has an open transaction or savepoint when apply_v2() is called, 
+**   it may revert the partially applied changeset by rolling it back.
+*/
+#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT   0x0001
+
 /* 
 ** CAPI3REF: Constants Passed To The Conflict Handler
 **
@@ -10091,7 +10518,162 @@
 #define SQLITE_CHANGESET_REPLACE    1
 #define SQLITE_CHANGESET_ABORT      2
 
+/* 
+** CAPI3REF: Rebasing changesets
+** EXPERIMENTAL
+**
+** Suppose there is a site hosting a database in state S0. And that
+** modifications are made that move that database to state S1 and a
+** changeset recorded (the "local" changeset). Then, a changeset based
+** on S0 is received from another site (the "remote" changeset) and 
+** applied to the database. The database is then in state 
+** (S1+"remote"), where the exact state depends on any conflict
+** resolution decisions (OMIT or REPLACE) made while applying "remote".
+** Rebasing a changeset is to update it to take those conflict 
+** resolution decisions into account, so that the same conflicts
+** do not have to be resolved elsewhere in the network. 
+**
+** For example, if both the local and remote changesets contain an
+** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)":
+**
+**   local:  INSERT INTO t1 VALUES(1, 'v1');
+**   remote: INSERT INTO t1 VALUES(1, 'v2');
+**
+** and the conflict resolution is REPLACE, then the INSERT change is
+** removed from the local changeset (it was overridden). Or, if the
+** conflict resolution was "OMIT", then the local changeset is modified
+** to instead contain:
+**
+**           UPDATE t1 SET b = 'v2' WHERE a=1;
+**
+** Changes within the local changeset are rebased as follows:
+**
+** <dl>
+** <dt>Local INSERT<dd>
+**   This may only conflict with a remote INSERT. If the conflict 
+**   resolution was OMIT, then add an UPDATE change to the rebased
+**   changeset. Or, if the conflict resolution was REPLACE, add
+**   nothing to the rebased changeset.
+**
+** <dt>Local DELETE<dd>
+**   This may conflict with a remote UPDATE or DELETE. In both cases the
+**   only possible resolution is OMIT. If the remote operation was a
+**   DELETE, then add no change to the rebased changeset. If the remote
+**   operation was an UPDATE, then the old.* fields of change are updated
+**   to reflect the new.* values in the UPDATE.
+**
+** <dt>Local UPDATE<dd>
+**   This may conflict with a remote UPDATE or DELETE. If it conflicts
+**   with a DELETE, and the conflict resolution was OMIT, then the update
+**   is changed into an INSERT. Any undefined values in the new.* record
+**   from the update change are filled in using the old.* values from
+**   the conflicting DELETE. Or, if the conflict resolution was REPLACE,
+**   the UPDATE change is simply omitted from the rebased changeset.
+**
+**   If conflict is with a remote UPDATE and the resolution is OMIT, then
+**   the old.* values are rebased using the new.* values in the remote
+**   change. Or, if the resolution is REPLACE, then the change is copied
+**   into the rebased changeset with updates to columns also updated by
+**   the conflicting remote UPDATE removed. If this means no columns would 
+**   be updated, the change is omitted.
+** </dl>
+**
+** A local change may be rebased against multiple remote changes 
+** simultaneously. If a single key is modified by multiple remote 
+** changesets, they are combined as follows before the local changeset
+** is rebased:
+**
+** <ul>
+**    <li> If there has been one or more REPLACE resolutions on a
+**         key, it is rebased according to a REPLACE.
+**
+**    <li> If there have been no REPLACE resolutions on a key, then
+**         the local changeset is rebased according to the most recent
+**         of the OMIT resolutions.
+** </ul>
+**
+** Note that conflict resolutions from multiple remote changesets are 
+** combined on a per-field basis, not per-row. This means that in the 
+** case of multiple remote UPDATE operations, some fields of a single 
+** local change may be rebased for REPLACE while others are rebased for 
+** OMIT.
+**
+** In order to rebase a local changeset, the remote changeset must first
+** be applied to the local database using sqlite3changeset_apply_v2() and
+** the buffer of rebase information captured. Then:
+**
+** <ol>
+**   <li> An sqlite3_rebaser object is created by calling 
+**        sqlite3rebaser_create().
+**   <li> The new object is configured with the rebase buffer obtained from
+**        sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure().
+**        If the local changeset is to be rebased against multiple remote
+**        changesets, then sqlite3rebaser_configure() should be called
+**        multiple times, in the same order that the multiple
+**        sqlite3changeset_apply_v2() calls were made.
+**   <li> Each local changeset is rebased by calling sqlite3rebaser_rebase().
+**   <li> The sqlite3_rebaser object is deleted by calling
+**        sqlite3rebaser_delete().
+** </ol>
+*/
+typedef struct sqlite3_rebaser sqlite3_rebaser;
+
 /*
+** CAPI3REF: Create a changeset rebaser object.
+** EXPERIMENTAL
+**
+** Allocate a new changeset rebaser object. If successful, set (*ppNew) to
+** point to the new object and return SQLITE_OK. Otherwise, if an error
+** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew) 
+** to NULL. 
+*/
+SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew);
+
+/*
+** CAPI3REF: Configure a changeset rebaser object.
+** EXPERIMENTAL
+**
+** Configure the changeset rebaser object to rebase changesets according
+** to the conflict resolutions described by buffer pRebase (size nRebase
+** bytes), which must have been obtained from a previous call to
+** sqlite3changeset_apply_v2().
+*/
+SQLITE_API int sqlite3rebaser_configure(
+  sqlite3_rebaser*, 
+  int nRebase, const void *pRebase
+); 
+
+/*
+** CAPI3REF: Rebase a changeset
+** EXPERIMENTAL
+**
+** Argument pIn must point to a buffer containing a changeset nIn bytes
+** in size. This function allocates and populates a buffer with a copy
+** of the changeset rebased rebased according to the configuration of the
+** rebaser object passed as the first argument. If successful, (*ppOut)
+** is set to point to the new buffer containing the rebased changset and 
+** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
+** responsibility of the caller to eventually free the new buffer using
+** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
+** are set to zero and an SQLite error code returned.
+*/
+SQLITE_API int sqlite3rebaser_rebase(
+  sqlite3_rebaser*,
+  int nIn, const void *pIn, 
+  int *pnOut, void **ppOut 
+);
+
+/*
+** CAPI3REF: Delete a changeset rebaser object.
+** EXPERIMENTAL
+**
+** Delete the changeset rebaser object and all associated resources. There
+** should be one call to this function for each successful invocation
+** of sqlite3rebaser_create().
+*/
+SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p); 
+
+/*
 ** CAPI3REF: Streaming Versions of API functions.
 **
 ** The six streaming API xxx_strm() functions serve similar purposes to the 
@@ -10100,6 +10682,7 @@
 ** <table border=1 style="margin-left:8ex;margin-right:8ex">
 **   <tr><th>Streaming function<th>Non-streaming equivalent</th>
 **   <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply] 
+**   <tr><td>sqlite3changeset_apply_strm_v2<td>[sqlite3changeset_apply_v2] 
 **   <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat] 
 **   <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert] 
 **   <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start] 
@@ -10195,6 +10778,23 @@
   ),
   void *pCtx                      /* First argument passed to xConflict */
 );
+SQLITE_API int sqlite3changeset_apply_v2_strm(
+  sqlite3 *db,                    /* Apply change to "main" db of this handle */
+  int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
+  void *pIn,                                          /* First arg for xInput */
+  int(*xFilter)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    const char *zTab              /* Table name */
+  ),
+  int(*xConflict)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
+    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
+  ),
+  void *pCtx,                     /* First argument passed to xConflict */
+  void **ppRebase, int *pnRebase,
+  int flags
+);
 SQLITE_API int sqlite3changeset_concat_strm(
   int (*xInputA)(void *pIn, void *pData, int *pnData),
   void *pInA,
@@ -10231,6 +10831,13 @@
 SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
     int (*xOutput)(void *pOut, const void *pData, int nData), 
     void *pOut
+);
+SQLITE_API int sqlite3rebaser_rebase_strm(
+  sqlite3_rebaser *pRebaser,
+  int (*xInput)(void *pIn, void *pData, int *pnData),
+  void *pIn,
+  int (*xOutput)(void *pOut, const void *pData, int nData),
+  void *pOut
 );
 
 
diff --git a/cbits/sqlite3ext.h b/cbits/sqlite3ext.h
--- a/cbits/sqlite3ext.h
+++ b/cbits/sqlite3ext.h
@@ -295,6 +295,21 @@
   int (*vtab_nochange)(sqlite3_context*);
   int (*value_nochange)(sqlite3_value*);
   const char *(*vtab_collation)(sqlite3_index_info*,int);
+  /* Version 3.24.0 and later */
+  int (*keyword_count)(void);
+  int (*keyword_name)(int,const char**,int*);
+  int (*keyword_check)(const char*,int);
+  sqlite3_str *(*str_new)(sqlite3*);
+  char *(*str_finish)(sqlite3_str*);
+  void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
+  void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
+  void (*str_append)(sqlite3_str*, const char *zIn, int N);
+  void (*str_appendall)(sqlite3_str*, const char *zIn);
+  void (*str_appendchar)(sqlite3_str*, int N, char C);
+  void (*str_reset)(sqlite3_str*);
+  int (*str_errcode)(sqlite3_str*);
+  int (*str_length)(sqlite3_str*);
+  char *(*str_value)(sqlite3_str*);
 };
 
 /*
@@ -563,8 +578,23 @@
 #define sqlite3_value_pointer          sqlite3_api->value_pointer
 /* Version 3.22.0 and later */
 #define sqlite3_vtab_nochange          sqlite3_api->vtab_nochange
-#define sqlite3_value_nochange         sqltie3_api->value_nochange
-#define sqlite3_vtab_collation         sqltie3_api->vtab_collation
+#define sqlite3_value_nochange         sqlite3_api->value_nochange
+#define sqlite3_vtab_collation         sqlite3_api->vtab_collation
+/* Version 3.24.0 and later */
+#define sqlite3_keyword_count          sqlite3_api->keyword_count
+#define sqlite3_keyword_name           sqlite3_api->keyword_name
+#define sqlite3_keyword_check          sqlite3_api->keyword_check
+#define sqlite3_str_new                sqlite3_api->str_new
+#define sqlite3_str_finish             sqlite3_api->str_finish
+#define sqlite3_str_appendf            sqlite3_api->str_appendf
+#define sqlite3_str_vappendf           sqlite3_api->str_vappendf
+#define sqlite3_str_append             sqlite3_api->str_append
+#define sqlite3_str_appendall          sqlite3_api->str_appendall
+#define sqlite3_str_appendchar         sqlite3_api->str_appendchar
+#define sqlite3_str_reset              sqlite3_api->str_reset
+#define sqlite3_str_errcode            sqlite3_api->str_errcode
+#define sqlite3_str_length             sqlite3_api->str_length
+#define sqlite3_str_value              sqlite3_api->str_value
 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
 
 #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,3 +1,11 @@
+v2.3.24:
+	* Upgrade embedded sqlite3 library to 3.24.0.
+	* Add faster `stepNoCB` function for statements that don't callback to Haskell functions.
+	* Use faster "unsafe" FFI calls for the following functions:
+	  reset, blobOpen, blobClose, blobReopen, blobRead, blobWrite, backupStep, errcode, errmsg
+	  as they are frequently used and don't callback to Haskell functions.
+	* Use faster Haskell memory allocator in blobRead function.
+
 v2.3.23:
 	* Add Semigroup instance to support GHC 8.4.1 (thanks @gwils)
 	* Build clean up for Android support (thanks @kmicklas)
diff --git a/direct-sqlite.cabal b/direct-sqlite.cabal
--- a/direct-sqlite.cabal
+++ b/direct-sqlite.cabal
@@ -1,126 +1,108 @@
-name: direct-sqlite
-version: 2.3.23
-build-type: Simple
-license: BSD3
-license-file: LICENSE
-copyright: Copyright (c) 2012, 2013 Irene Knapp
-author: Irene Knapp <irene.knapp@icloud.com>
-maintainer: Janne Hellsten <jjhellst@gmail.com>
-homepage: https://github.com/IreneKnapp/direct-sqlite
-bug-reports: https://github.com/IreneKnapp/direct-sqlite/issues/new
-category: Database
-synopsis: Low-level binding to SQLite3.  Includes UTF8 and BLOB support.
-Cabal-version: >= 1.10
-description:
-  This package is not very different from the other SQLite3 bindings out
-  there, but it fixes a few deficiencies I was finding.  As compared to
-  bindings-sqlite3, it is slightly higher-level, in that it supports
-  marshalling of data values to and from the database.  In particular, it
-  supports strings encoded as UTF8, and BLOBs represented as ByteStrings.
-
-extra-source-files:
-  cbits/sqlite3.c
-  cbits/sqlite3.h
-  cbits/sqlite3ext.h
-  changelog
+name:               direct-sqlite
+version:            2.3.24
+synopsis:           Low-level binding to SQLite3.  Includes UTF8 and BLOB support.
+description:        This package is not very different from the other SQLite3 bindings out
+                    there, but it fixes a few deficiencies I was finding.  As compared to
+                    bindings-sqlite3, it is slightly higher-level, in that it supports
+                    marshalling of data values to and from the database.  In particular,
+                    it supports strings encoded as UTF8, and BLOBs represented as
+                    ByteStrings.
+license:            BSD3
+license-file:       LICENSE
+copyright:          Copyright (c) 2012 - 2014 Irene Knapp,
+                                  2014 - 2018 Janne Hellsten,
+                                  2018 - 2019 Sergey Bushnyak
+author:             Irene Knapp <irene.knapp@icloud.com>
+maintainer:         Sergey Bushnyak <sergey.bushnyak@sigrlami.eu>
+category:           Database
+homepage:           https://github.com/IreneKnapp/direct-sqlite
+bug-reports:        https://github.com/IreneKnapp/direct-sqlite/issues/new
+build-type:         Simple
+extra-source-files: cbits/sqlite3.c
+                    cbits/sqlite3.h
+                    cbits/sqlite3ext.h
+                    changelog
+cabal-version:      >= 1.10
 
-Source-Repository head
-  type: git
+source-repository head
+  type:     git
   location: git://github.com/IreneKnapp/direct-sqlite.git
 
 flag systemlib
+  default:     False
   description: Use the system-wide sqlite library
-  default: False
 
 flag fulltextsearch
+  default:     True
   description: Enable full-text search when using the bundled sqlite library
-  default: True
 
 flag urifilenames
+  default:     True
   description: Enable URI filenames when using the bundled sqlite library
-  default: True
 
 flag haveusleep
+  default:     True
   description: Enable use of os function usleep.
-  default: True
 
 flag json1
+  default:     True
   description: Enable json1 extension.
-  default: True
 
-Library
-  exposed-modules:
-    Database.SQLite3
-    Database.SQLite3.Direct
-    Database.SQLite3.Bindings
-    Database.SQLite3.Bindings.Types
+library
+  exposed-modules:  Database.SQLite3
+                    Database.SQLite3.Bindings
+                    Database.SQLite3.Bindings.Types
+                    Database.SQLite3.Direct
+  build-depends:    base       >= 4.1 && < 5
+                  , bytestring >= 0.9.2.1
+                  , semigroups >= 0.18 && < 0.19
+                  , text       >= 0.11
+  default-language: Haskell2010
+  include-dirs:     .
+  ghc-options:      -Wall -fwarn-tabs
 
-  if flag(systemlib) {
-    cpp-options: -Ddirect_sqlite_systemlib
+  if flag(systemlib)
     extra-libraries: sqlite3
-  } else {
-    if !os(windows) && !os(android) {
+    cpp-options:     -Ddirect_sqlite_systemlib
+  else
+    c-sources:        cbits/sqlite3.c
+    install-includes: sqlite3.h, sqlite3ext.h
+    include-dirs:     cbits
+
+    if !os(windows) && !os(android)
       extra-libraries: pthread
-    }
-    c-sources: cbits/sqlite3.c
-    include-dirs: cbits
-    install-includes:
-      sqlite3.h
-      sqlite3ext.h
 
-    if flag(fulltextsearch) {
-      cc-options: -DSQLITE_ENABLE_FTS3
-                  -DSQLITE_ENABLE_FTS3_PARENTHESIS
-                  -DSQLITE_ENABLE_FTS4
-                  -DSQLITE_ENABLE_FTS5
-    }
+    if flag(fulltextsearch)
+      cc-options: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
+                  -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
 
-    if flag(urifilenames) {
+    if flag(urifilenames)
       cc-options: -DSQLITE_USE_URI
-    }
 
-    if flag(haveusleep) {
-       cc-options: -DHAVE_USLEEP
-    }
+    if flag(haveusleep)
+      cc-options: -DHAVE_USLEEP
 
-    if flag(json1) {
+    if flag(json1)
       cc-options: -DSQLITE_ENABLE_JSON1
-    }
-  }
 
-  include-dirs: .
-  build-depends: base >= 4.1 && < 5,
-                 bytestring >= 0.9.2.1,
-                 semigroups >= 0.18 && < 0.19,
-                 text >= 0.11
-  ghc-options: -Wall -fwarn-tabs
-  default-language: Haskell2010
-
-
 test-suite test
-  type:           exitcode-stdio-1.0
-
-  hs-source-dirs: test
-  main-is:        Main.hs
-  other-modules:
-    StrictEq
-
-  ghc-options: -Wall -threaded -fno-warn-name-shadowing -fno-warn-unused-do-bind
-
-  default-language: Haskell2010
-
-  default-extensions: DeriveDataTypeable
-                    , NamedFieldPuns
-                    , OverloadedStrings
-                    , Rank2Types
-                    , RecordWildCards
-                    , ScopedTypeVariables
-
-  build-depends: base
-               , base16-bytestring
-               , bytestring
-               , directory
-               , HUnit
-               , direct-sqlite
-               , temporary
-               , text
+  type:               exitcode-stdio-1.0
+  main-is:            Main.hs
+  other-modules:      StrictEq
+  hs-source-dirs:     test
+  build-depends:      base
+                    , HUnit
+                    , base16-bytestring
+                    , bytestring
+                    , direct-sqlite
+                    , directory
+                    , temporary
+                    , text
+  default-language:   Haskell2010
+  default-extensions: Rank2Types
+                      ScopedTypeVariables
+                      NamedFieldPuns
+                      RecordWildCards
+                      OverloadedStrings
+                      DeriveDataTypeable
+  ghc-options:        -Wall -threaded -fno-warn-name-shadowing -fno-warn-unused-do-bind
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -96,7 +96,7 @@
   exec conn "--"
   Left SQLError{sqlError = ErrorError} <- try $ exec conn "/*"
     -- sqlite3_exec does not allow "/*" to be terminated by end of input,
-    -- but <http://www.sqlite.org/lang_comment.html> says it's fine.
+    -- but <https://www.sqlite.org/lang_comment.html> says it's fine.
   exec conn ";--\n;/**/"
   withConn $ \conn -> do
     -- Make sure all the statements passed to exec are executed.
